|
17938
|
781
|
46
|
2026-05-11T10:42:18.325369+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496138325_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"lines":[{"char_start":273,"char_count":32,"bounds":{"left":0.61702126,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.61702126,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.61702126,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.61702126,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.61702126,"top":0.0,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.61702126,"top":0.0015961692,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.61702126,"top":0.01915403,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.61702126,"top":0.03671189,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.61702126,"top":0.054269753,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.61702126,"top":0.07182761,"width":0.38297874,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.61702126,"top":0.08938547,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.61702126,"top":0.10694334,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.61702126,"top":0.1245012,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.61702126,"top":0.14205906,"width":0.38297874,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.61702126,"top":0.15961692,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.61702126,"top":0.17717478,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.61702126,"top":0.19473264,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.61702126,"top":0.2122905,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.61702126,"top":0.22984837,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.61702126,"top":0.24740623,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.61702126,"top":0.26496407,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.61702126,"top":0.28252193,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17937
|
780
|
47
|
2026-05-11T10:42:18.325329+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496138325_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
17935
|
NULL
|
NULL
|
NULL
|
|
17936
|
781
|
45
|
2026-05-11T10:42:13.595430+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496133595_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorTOOISWindo PhostormVIewINavicarecodeLaravelKeractorTOOISWindowmelpFV faVsco.js°9 JY-20725-handle-HS-search-rate-limProiect© TrackRecordingFileSiz© TrackRecordingSizeEnT. ValidateSmitProspect:D AjReports0 CalendarConference0 Crm@ bullnorn0 Close0 Copper>J Crmobiects_ DecorareAcuivilyDummyHelpersv h HubspotAccountSvncStrate>D Actionsa ContactsuncStratedm Fields• Malournal1 Metadatalv OpportunitySyncSt>MConcerns.(c) Hubsnotl actMoC HubspotLastMo(C) Hubsnotl actMo© HubspotLastMo(C) Hubsnotl actMo(C) HubsnotSinaleS© HubspotSyncStr© HubspotWebhoo~ M Padination© HubspotPaginat© PaginationConfi© PaginationState> D ProspectSearchStr:› D Redisv D ServiceTraits() OpportunitvSvnc() SvncCrmEntitiesT SuncFieldstirait.T. WriteCrmTrait.o• M UtilsM WebhookC) BatchSvncCollectot(c) RatchSvncRedisSec) Client nhr(C) ClocedDea|Stadecc@ DoalFieldsService rC) TrackAutomated ReportGeneratedzventonpT SyncCrmEntitiesTrait.phpCachedcrmservicebecorator.ongoveryaeuvitycrmlaskJoo.pnp© Job.phpBadkequest.php© PaginationState.phgclass Cllent extends Baseclient 1mpLements Hubspotcllentintertace230public function getPaginatedDataGenerator(Nwroo242)243244)&. scotal,&: $lastRecordId24612472481* Execute a search request against Hubsoot cri obnects with rate limitina.2501* aparam strina SobnectiTupe The obnect tupe 'deals', 'compantes'.'contacts', 'calls')@param array<string, mixed> $payload The search payload with filters, sorts, properties, etc* Greturn arrou The search'total', "naonno'keus* Athrows RateLimitExcention When rate Limit is hitOn APt errors256 0public function search(string SobjectType, array Spayload): arraySendnnint = cpf.•RASF WIRIAneturn_Sthic->pyecuteRequest/function0uce (Sendnoint Snavloadh&Sresponse = $this->getInstance->getClient->request( method: 'POST', Sendpoint, ['json' => $payload]):return Sresponse->toArrayO:266* acnrows vealapzexceptlon* dchrows Crmexceptionpublic function getupportun1tybvld(string Scrmid, array Stields: array|/1est(fn () => $this-Sdeal = Sthis->aetNewinstance@->crmO->dealsO->basicAni@->getBvidnceo->crmo->dealso->oas1cAn1O->detividimoloded separaton• • Sfields)} catch (DealAniFycention Se) $Sthis-s1oa-sinfor1Huhsnot Satled to Fetch onnortunitvlSe->ae+Meçcane O1" suppont Dally • In 1h 10m100% LzP• Mon 11 May 13:42:13HandleHubspotRateLimitTest v« console (PROD]* console (EUl& console [STAGINGIw.19A(c) HubSpot/Service.onpA RateLimitException.ong© PaginationConfig.php743A68 V 3= laravel.log4 SF [jiminny@localhost]& HS_local [jiminny@localhost][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Date":["Thu,07 May 2026 14:21:15 GMT"],"Content-Type":["application/json;charset=utf-8"]."Transfer-Encoding": ["chunked"],"conneccion". Keep-alive"n"CF-Ray" : ["9f80deb8db60dc3a-SOF"],"CF-Cache-Status":"DYNAMIC")"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")accept-encoding"],"access-control-allow-credentials": "false").server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfn:desc="9-80de8ercodc3a-TAD""x-content-type-options": ["nosniff"]."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"])"Set-Cookie".[" cf bm=STUrtd0aXVrik50odaF6hZVYKhzTn0BidvMabeCtm0Y-1778163675-[IP_ADDRESS]-рT. ZaatDKxTae5zr8 2abBfWM00. ufZEXDZuHz2mBUFdzdo2aTHEs0)07-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["1"endnoints"•!\"url\":\"https:|V/\V/a.nel.cloudflare.com/\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZLzoYdxI%2BIxVpHmsKn30%2BKVA3mFIJ2m7YRECDGS\"group\":\"cf-nel\",\"max_age\":604800}"],"success_fraction\":0.01,"report_to\":\"cf-nel\"\"max_age\":604800}"],"Server": ["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab"."trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}I MIm T T111W Windsurf Teams 256:21 UTF-8 P 4 spaces ®...
|
NULL
|
-4974032155204697394
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorTOOISWindo PhostormVIewINavicarecodeLaravelKeractorTOOISWindowmelpFV faVsco.js°9 JY-20725-handle-HS-search-rate-limProiect© TrackRecordingFileSiz© TrackRecordingSizeEnT. ValidateSmitProspect:D AjReports0 CalendarConference0 Crm@ bullnorn0 Close0 Copper>J Crmobiects_ DecorareAcuivilyDummyHelpersv h HubspotAccountSvncStrate>D Actionsa ContactsuncStratedm Fields• Malournal1 Metadatalv OpportunitySyncSt>MConcerns.(c) Hubsnotl actMoC HubspotLastMo(C) Hubsnotl actMo© HubspotLastMo(C) Hubsnotl actMo(C) HubsnotSinaleS© HubspotSyncStr© HubspotWebhoo~ M Padination© HubspotPaginat© PaginationConfi© PaginationState> D ProspectSearchStr:› D Redisv D ServiceTraits() OpportunitvSvnc() SvncCrmEntitiesT SuncFieldstirait.T. WriteCrmTrait.o• M UtilsM WebhookC) BatchSvncCollectot(c) RatchSvncRedisSec) Client nhr(C) ClocedDea|Stadecc@ DoalFieldsService rC) TrackAutomated ReportGeneratedzventonpT SyncCrmEntitiesTrait.phpCachedcrmservicebecorator.ongoveryaeuvitycrmlaskJoo.pnp© Job.phpBadkequest.php© PaginationState.phgclass Cllent extends Baseclient 1mpLements Hubspotcllentintertace230public function getPaginatedDataGenerator(Nwroo242)243244)&. scotal,&: $lastRecordId24612472481* Execute a search request against Hubsoot cri obnects with rate limitina.2501* aparam strina SobnectiTupe The obnect tupe 'deals', 'compantes'.'contacts', 'calls')@param array<string, mixed> $payload The search payload with filters, sorts, properties, etc* Greturn arrou The search'total', "naonno'keus* Athrows RateLimitExcention When rate Limit is hitOn APt errors256 0public function search(string SobjectType, array Spayload): arraySendnnint = cpf.•RASF WIRIAneturn_Sthic->pyecuteRequest/function0uce (Sendnoint Snavloadh&Sresponse = $this->getInstance->getClient->request( method: 'POST', Sendpoint, ['json' => $payload]):return Sresponse->toArrayO:266* acnrows vealapzexceptlon* dchrows Crmexceptionpublic function getupportun1tybvld(string Scrmid, array Stields: array|/1est(fn () => $this-Sdeal = Sthis->aetNewinstance@->crmO->dealsO->basicAni@->getBvidnceo->crmo->dealso->oas1cAn1O->detividimoloded separaton• • Sfields)} catch (DealAniFycention Se) $Sthis-s1oa-sinfor1Huhsnot Satled to Fetch onnortunitvlSe->ae+Meçcane O1" suppont Dally • In 1h 10m100% LzP• Mon 11 May 13:42:13HandleHubspotRateLimitTest v« console (PROD]* console (EUl& console [STAGINGIw.19A(c) HubSpot/Service.onpA RateLimitException.ong© PaginationConfig.php743A68 V 3= laravel.log4 SF [jiminny@localhost]& HS_local [jiminny@localhost][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Date":["Thu,07 May 2026 14:21:15 GMT"],"Content-Type":["application/json;charset=utf-8"]."Transfer-Encoding": ["chunked"],"conneccion". Keep-alive"n"CF-Ray" : ["9f80deb8db60dc3a-SOF"],"CF-Cache-Status":"DYNAMIC")"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")accept-encoding"],"access-control-allow-credentials": "false").server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfn:desc="9-80de8ercodc3a-TAD""x-content-type-options": ["nosniff"]."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"])"Set-Cookie".[" cf bm=STUrtd0aXVrik50odaF6hZVYKhzTn0BidvMabeCtm0Y-1778163675-[IP_ADDRESS]-рT. ZaatDKxTae5zr8 2abBfWM00. ufZEXDZuHz2mBUFdzdo2aTHEs0)07-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["1"endnoints"•!\"url\":\"https:|V/\V/a.nel.cloudflare.com/\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZLzoYdxI%2BIxVpHmsKn30%2BKVA3mFIJ2m7YRECDGS\"group\":\"cf-nel\",\"max_age\":604800}"],"success_fraction\":0.01,"report_to\":\"cf-nel\"\"max_age\":604800}"],"Server": ["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab"."trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}I MIm T T111W Windsurf Teams 256:21 UTF-8 P 4 spaces ®...
|
17934
|
NULL
|
NULL
|
NULL
|
|
17935
|
780
|
46
|
2026-05-11T10:42:13.575262+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496133575_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV ( SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 18 m100% <78• Mon 11 May 13:42:13ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
NULL
|
7026778090282363683
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV ( SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 18 m100% <78• Mon 11 May 13:42:13ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17934
|
781
|
44
|
2026-05-11T10:42:12.295071+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496132295_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"lines":[{"char_start":273,"char_count":32,"bounds":{"left":0.61702126,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.61702126,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.61702126,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.61702126,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.61702126,"top":0.0,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.61702126,"top":0.0015961692,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.61702126,"top":0.01915403,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.61702126,"top":0.03671189,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.61702126,"top":0.054269753,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.61702126,"top":0.07182761,"width":0.38297874,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.61702126,"top":0.08938547,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.61702126,"top":0.10694334,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.61702126,"top":0.1245012,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.61702126,"top":0.14205906,"width":0.38297874,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.61702126,"top":0.15961692,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.61702126,"top":0.17717478,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.61702126,"top":0.19473264,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.61702126,"top":0.2122905,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.61702126,"top":0.22984837,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.61702126,"top":0.24740623,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.61702126,"top":0.26496407,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.61702126,"top":0.28252193,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17933
|
781
|
43
|
2026-05-11T10:42:09.292590+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496129292_m2.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Inherited members (⌘R)
Anonymous Classes (⌘I)
Lamb Inherited members (⌘R)
Anonymous Classes (⌘I)
Lambdas (⌘L)
loading…
Client.php...
|
[{"role":"AXCheckBox","text [{"role":"AXCheckBox","text":"Inherited members (⌘R)","depth":1,"bounds":{"left":0.5242686,"top":0.33998403,"width":0.052526597,"height":0.022346368},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Anonymous Classes (⌘I)","depth":1,"bounds":{"left":0.58011967,"top":0.33998403,"width":0.052526597,"height":0.022346368},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Lambdas (⌘L)","depth":1,"bounds":{"left":0.6359708,"top":0.33998403,"width":0.052526597,"height":0.022346368},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"loading…","depth":4,"bounds":{"left":0.5299202,"top":0.36472467,"width":0.023603724,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Client.php","depth":1,"bounds":{"left":0.5242686,"top":0.31364724,"width":0.19980054,"height":0.026336791},"on_screen":true,"role_description":"text"}]...
|
5797934796897005000
|
1410411586113665
|
visual_change
|
hybrid
|
NULL
|
Inherited members (⌘R)
Anonymous Classes (⌘I)
Lamb Inherited members (⌘R)
Anonymous Classes (⌘I)
Lambdas (⌘L)
loading…
Client.php
PhostormVIewINavicareCodeLaravelTOOISFV faVsco.js°9 JY-20725-handle-HS-search-rate-limroledeyC) TrackAutomated ReportGeneratedzventonp© TrackRecordingFileSiz© TrackRecordingSizeEnT. ValidateSmitProspect:T SyncCrmEntitiesTrait.php© CheckAndRetryRemoteMatch.phpAjReportsBadkequest.phpC) Kernel.php© PaginationState.phg0 Calendarn Conference1300 Crm@ bullnorn> OJ Close_copper>J Crmobiects_ DecorateAcuiviiy• Dummy143144145) Helpersv h Hubspot147AccountSvncStrate>D Actionsa ContactsvncStraterM Fields• M lournal1 Metadatalv OpportunitySyncSt>MConcerns.(c) Hubsnotl actMoC HubspotLastMo(C) Hubsnotl actMo© HubspotLastMo(C) Hubsnotl actMo© HubspotSingleS© HubspotSyncStr© HubspotWebhoo~ M Padination© HubspotPaginat© PaginationConfi(C) PaqinationState> D ProspectSearchStr:> D Redisv D ServiceTraitsTOnoortunitvsvnc() SvncCrmEntities176171T SuncFieldstirait.() WriteCrmTrait.n174• M UtilsM WebhookC) BatchSvncCollectot177(c) RatchSvncRedisSec) Client nho(C) ClocedDea|Stadecs@ DoalFieldsService rTacts naccod. 12 (20 minutes aao)class Cllent extends Baseclient 1mpLements Hubspotcllentintertacepublic function parseRetryAfter(Throwable $e): intifcis arrav(Svalue))Svalve = Svaluel0l ?> nult.if Gis numeric($value)) {return (int) $valve;Spolicy = $this->parsePolicy($e);if (Spolicy ==='TEN_SECONDLY_ROLLING') {notunn 10+if (Spolicy === 'SECONDLY') {return 1:if (Spolicy === 'DAILY LIMIT') {return 600Sthis->log->warning('[Hubspotl No retry-after header or policy name found. using default'. ['exception class' => qet class(Se).return 10:public function parsePolicy(Throwable $e): ?stringif d method existsSe.method:"aetResnonseBodv'))^netunn null.$body = $e->getResponseBodyO:if (is string($body)) {$body = ison_ decode($body,associative: true) ?? (]:if (! is array($body)) {Spolicy = Sbodví'policvName'] 22 Sbody[ 'policy'] 2> Sbodvl 'context'][ 'policyName'] 22 null:return is string(Spolicv) 2 strtoupper(Spolicy) : null:(c) HubSpot/Service.onpoveryaeuvitycrmlaskJoo.pnpA RateLimitException.ong© PaginationConfig.phpA3468 V3A1 MIM 1" suppont Dally • In 1h 10m100% LzP• Mon 11 May 13:42:08HandleHubspotRateLimitTest v« console (PROD]* console (EUl& console [STAGINGIw.19A= laravel.log4 SF [jiminny@localhost]& HS_local [jiminny@localhost][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Date":["Thu,07 May 2026 14:21:15 GMT"],"Content-Type":["application/json;charset=utf-8"]."Tnancfen-Encoding": ["chunked"J,"conneccion". Keep-alive"n"CF-Ray" : ["9f80deb8db60dc3a-SOF"],"CF-Cache-Status":"DYNAMIC")"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")accept-encoding"],access-control-allow-credentials": "false",server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfn:desc="9-80de8ercodcSa-TAD"'x-content-type-options": ["nosniff"]."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"]"Set-Cookie".[" cf bm=STUrtd0aXVrik50odaF6hZVYKhzTn0BidvMabeCtm0Y-1778163675-[IP_ADDRESS]-рT. ZaatDKxTae5zr8 2abBfWM00. ufZEXDZuHz2mBUFdzdo2aTHEs0)07-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f","endnoints"•!\"url\":\"https:|V/\V/a.nel.cloudflare.com/\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZLzoYdxI%2BIxVpHmsKn30%2BKVA3mFIJ2m7YRECDGS\"group\":\"cf-nel\",\"max_age\":604800}"],"success_fraction\":0.01,"repоrт_со ."cт-nel\"\"max_age\":604800}"],"Server": ["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab".id": "c7ab8365-903f-46d4-9403-0e5b551e3545"}W Windsurf Teams 76:28 UTF-8 P 4 spaces ®...
|
17931
|
NULL
|
NULL
|
NULL
|
|
17932
|
780
|
45
|
2026-05-11T10:42:05.083946+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496125083_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
17930
|
NULL
|
NULL
|
NULL
|
|
17931
|
781
|
42
|
2026-05-11T10:42:03.662423+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496123662_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"lines":[{"char_start":273,"char_count":32,"bounds":{"left":0.61702126,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.61702126,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.61702126,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.61702126,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.61702126,"top":0.0,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.61702126,"top":0.0015961692,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.61702126,"top":0.01915403,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.61702126,"top":0.03671189,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.61702126,"top":0.054269753,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.61702126,"top":0.07182761,"width":0.38297874,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.61702126,"top":0.08938547,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.61702126,"top":0.10694334,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.61702126,"top":0.1245012,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.61702126,"top":0.14205906,"width":0.38297874,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.61702126,"top":0.15961692,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.61702126,"top":0.17717478,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.61702126,"top":0.19473264,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.61702126,"top":0.2122905,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.61702126,"top":0.22984837,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.61702126,"top":0.24740623,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.61702126,"top":0.26496407,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.61702126,"top":0.28252193,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1006337435740056067
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17930
|
780
|
44
|
2026-05-11T10:42:03.652426+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496123652_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1006337435740056067
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17929
|
781
|
41
|
2026-05-11T10:42:00.787768+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496120787_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"lines":[{"char_start":273,"char_count":32,"bounds":{"left":0.61702126,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.61702126,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.61702126,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.61702126,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.61702126,"top":0.0,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.61702126,"top":0.0015961692,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.61702126,"top":0.01915403,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.61702126,"top":0.03671189,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.61702126,"top":0.054269753,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.61702126,"top":0.07182761,"width":0.38297874,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.61702126,"top":0.08938547,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.61702126,"top":0.10694334,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.61702126,"top":0.1245012,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.61702126,"top":0.14205906,"width":0.38297874,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.61702126,"top":0.15961692,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.61702126,"top":0.17717478,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.61702126,"top":0.19473264,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.61702126,"top":0.2122905,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.61702126,"top":0.22984837,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.61702126,"top":0.24740623,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.61702126,"top":0.26496407,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.61702126,"top":0.28252193,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
17927
|
NULL
|
NULL
|
NULL
|
|
17928
|
780
|
43
|
2026-05-11T10:42:00.759521+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496120759_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
17926
|
NULL
|
NULL
|
NULL
|
|
17927
|
781
|
40
|
2026-05-11T10:41:59.243647+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496119243_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1006337435740056067
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17926
|
780
|
42
|
2026-05-11T10:41:59.237018+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496119237_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5408622603018220958
|
5225697106764630116
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17925
|
780
|
41
|
2026-05-11T10:41:45.479493+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496105479_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
17923
|
NULL
|
NULL
|
NULL
|
|
17924
|
781
|
39
|
2026-05-11T10:41:44.689116+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496104689_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"lines":[{"char_start":273,"char_count":32,"bounds":{"left":0.61702126,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.61702126,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.61702126,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.61702126,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.61702126,"top":0.0,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.61702126,"top":0.0015961692,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.61702126,"top":0.01915403,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.61702126,"top":0.03671189,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.61702126,"top":0.054269753,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.61702126,"top":0.07182761,"width":0.38297874,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.61702126,"top":0.08938547,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.61702126,"top":0.10694334,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.61702126,"top":0.1245012,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.61702126,"top":0.14205906,"width":0.38297874,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.61702126,"top":0.15961692,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.61702126,"top":0.17717478,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.61702126,"top":0.19473264,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.61702126,"top":0.2122905,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.61702126,"top":0.22984837,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.61702126,"top":0.24740623,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.61702126,"top":0.26496407,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.61702126,"top":0.28252193,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
17922
|
NULL
|
NULL
|
NULL
|
|
17923
|
780
|
40
|
2026-05-11T10:41:39.079423+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496099079_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7623778648713633268
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17922
|
781
|
38
|
2026-05-11T10:41:37.253389+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496097253_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"lines":[{"char_start":273,"char_count":32,"bounds":{"left":0.61702126,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.61702126,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.61702126,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.61702126,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.61702126,"top":0.0,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.61702126,"top":0.0015961692,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.61702126,"top":0.01915403,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.61702126,"top":0.03671189,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.61702126,"top":0.054269753,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.61702126,"top":0.07182761,"width":0.38297874,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.61702126,"top":0.08938547,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.61702126,"top":0.10694334,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.61702126,"top":0.1245012,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.61702126,"top":0.14205906,"width":0.38297874,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.61702126,"top":0.15961692,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.61702126,"top":0.17717478,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.61702126,"top":0.19473264,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.61702126,"top":0.2122905,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.61702126,"top":0.22984837,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.61702126,"top":0.24740623,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.61702126,"top":0.26496407,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.61702126,"top":0.28252193,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1006337435740056067
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17921
|
780
|
39
|
2026-05-11T10:41:37.219655+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496097219_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2910083726154500178
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project...
|
17919
|
NULL
|
NULL
|
NULL
|
|
17920
|
781
|
37
|
2026-05-11T10:41:35.655527+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496095655_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5515292,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"bounds":{"left":0.56150264,"top":0.15003991,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5738032,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"}]...
|
2407769031564044197
|
5225697106764630116
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19...
|
17918
|
NULL
|
NULL
|
NULL
|
|
17919
|
780
|
38
|
2026-05-11T10:41:35.129052+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496095129_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6243931637791501581
|
6378618611371477092
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17918
|
781
|
36
|
2026-05-11T10:41:33.539938+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496093539_m2.jpg...
|
PhpStorm
|
faVsco.js – JiminnyDebugCommand.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5685266402682420683
|
-8926130836387591936
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-linroledeyC. Iteratel IcersCommandC) Jiminnycacheclearco) Jiminnysettncryptedl© JiminnyTokenInfoCom© MakeslackLIvecoachir 348© ManageScimForTeam.C) MarkBranchForEnviror 366C) MuteOrqanizerChanne 367c) PhoApm.php(C) PropagateCoachingFe 369C) PuraeConterences.ohr zzalc) PurceSoit Deletedeodc) PuroesvncBatchescor z7.© RecalculateDealRisksC 372(C) RemoveDeleteMarkers 77:© RemoveExpiredNudge: 374© RemoveUnusedParticil 375© ResetElasticSearch.ph 376• KestoreAcuvLyemrIe 377© RestoreActivityTypeCc 378© RunAiCallScoringForUr 379Uopelerenwmie crelnie© SendNudgeExpirationV 381© SyncActivity.php(e) Trackimoorted.onp© wnichworkerisworkint 384m Scheduling© Kernel.php> D Contracts> D DomainDTO> 0 Emails> C Enumsv D Eventsv M Activities> _ ActivitvProvidenM AiAutomation> AudidD BotsD CoachingIM ConferencasM Connections• M CrmC) ActivitvCancelled.n 401l© ActivityCancelledA: 402(C) Activitvl eadGonvet /0zl@ ActivitvLinkedToCri 404© ActivityLogged.php 409© ActivityScheduled.r 406© AutoLogActivity.ph| 407Tacts naccod. 12 (20 minutes aao)Windowmelp" suppont Dally • In 1h 15 m100% L2• Mon 11 May 13:41:33HandleHubspotRateLimitTest v« console (PROD]* console (EUl& console (STAGINGIw.19A© UserAutomatedReportsController.php© PlaybackController.php(C) Hubsnot/Service.ohn(c) HubSpot/Service.onpT DeleteCrmEntityTrait.php© VerifyActivityCrmTaskJob.php© RateLimitExceptionTest.php© CheckAndRetryRemoteMatch.php© Job.phpC) CrmActivityService.pnp© RateLimitException.pnp© MatchCrmData.php© Crmobiectskesolver.php© ProviderRateLimiter.php© PaginationConfig.phpA5 A133 V11 ABadkequest.phpclass JiminnyDebuqcommand extends Commandprivate function rateLimitoScrmService->sync0pportunity('374720564'):ScrmService->matchRvName('Robot')1usageprivate function simulateMatchActivityStorm(int SteamId = 2, int Scount = 100): voidSrean - leam.. randsceanloscont10 = steam->gecurmuontiquraciononSactivities = Activity::queryo'crm contiquration 10', scont10->qetld0e->orderbybesc col->Limit (Scount))in:"10')->aetosSthis->info( string: "Dispatching {Sactivities->count@} MatchActivitvCrmData iobs (portal={Sconfig->qetTd@})"):foreach Sactivities as sactivity) <MatchActivitvCrmData:•dispatch(is: Sactivitv->cetido, Sconfio, true):Sthis->info( string: 'Done. Watch logs and run jiminny:debug observeRateLimit to inspect cache state.'):no usadesprivate function simulateVerifyTaskStorm(int Steamid = 2, int Scount = 100): voidSactivities = Activity::queryOIteam idi Cteamtd)l-swheneNo+Nul1/ columns: "enm nnoviden id)lalonkwlloceelidt->Limit($count)->getSthis->info( string: "Dispatching {Sactivities->countO} VerifvActivityCrmTaskJob jobs"):foreach Sactivities as sactivity) <VerifvActivityCrmTaskJob::dispatch(Sactivity->qetId0):Sthis->info string:"Done.")= custom.log Xlaravel.log4 SF [jiminny@localhost]& HS_local [jiminny@localhost][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Date":["Thu,07 May 2026 14:21:15 GMT"],"Content-Type":["application/json;charset=utf-8"]."Transfer-Encoding": ["chunked"],"conneccion". Keep-alive"n"CF-Ray" : ["9f80deb8db60dc3a-SOF"],"CF-Cache-Status":"DYNAMIC"]"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")accept-encoding"],"access-control-allow-credentials": "false")"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfn:desc="9-80de8ercodcSa-TAD"'"x-content-type-options": ["nosniff"]."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"])"Set-Cookie".[" cf bm=STUrtd0aXVrik50odaF6hZVYKhzTn0BidvMabeCtm0Y-1778163675-[IP_ADDRESS]-рT. ZaatDKxTae5zr8 2abBfWM00. ufZEXDZuHz2mBUFdzdo2aTHEs0)07-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f","endnoints"•!\"url\":\"https:|V/\V/a.nel.cloudflare.com/\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZLzoYdxI%2BIxVpHmsKn30%2BKVA3mFIJ2m7YRECDGS\"group\":\"cf-nel\",\"max_age\":604800}"],"success_fraction\":0.01,"report_to\":\"cf-nel\"\"max_age\":604800}"],"Server": ["cloudflare"]}} {"correlation id":"95236535-ec98-4541-b92a-adfa73b69eab"."trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}W Windsurf Teams 379:28 UTF-8 P 4 spaces ®...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17917
|
780
|
37
|
2026-05-11T10:41:33.538226+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496093538_m1.jpg...
|
PhpStorm
|
faVsco.js – JiminnyDebugCommand.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5870622292910750321
|
-8348263803913827968
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
SlackFileEditViewGoHistoryWindowHelpDOCKERO ₴1DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:33ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay Ivanov3Aneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
17914
|
NULL
|
NULL
|
NULL
|
|
17916
|
781
|
35
|
2026-05-11T10:41:28.538262+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496088538_m2.jpg...
|
PhpStorm
|
faVsco.js – JiminnyDebugCommand.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
5
133
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\Crm\Delete\VerifyActivityCrmTaskJob;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
UserPilotClient $userPilotClient
): void {
// Choose ONE of the following to run, then comment out the others.
// 1) Dispatch a storm of MatchActivityCrmData jobs against team 2
$this->simulateMatchActivityStorm(teamId: 2, count: 100);
// 2) Dispatch a storm of VerifyActivityCrmTaskJob jobs (simulates DeleteCrmEntityTrait fan-out)
// $this->simulateVerifyTaskStorm(teamId: 2, count: 100);
// 3) Inspect Redis circuit-breaker state for the team's HubSpot portal
// $this->observeRateLimitCache(teamId: 2);
// 4) Make 3 synchronous matchByName calls (foreground, hits API directly)
// $this->rateLimit();
exit(1);
$report = AutomatedReport::find(71);
$last = AutomatedReportResult::query()
->where('report_id', $report->getId())
->whereIn('status', [AutomatedReportResult::STATUS_DEFAULT, AutomatedReportResult::STATUS_FAILED])
// ->where('reason', '!=', AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES)
->whereDate('created_at', CarbonImmutable::now()->toDateString())
->latest()
->first();
$this->info("Last: {$last->getId()}");
exit(1);
$user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
$payload = [
'report_type' => 'ask_jiminny',
'frequency' => 'weekly',
];
$userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);
exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
private function rateLimit()
{
$team = Team::find(2);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
for ($i = 0 ; $i < 3; $i++) {
// if ($i % 25 === 0) {
// $this->info("Syncing opportunity {$i}");
$this->info("Matching contact {$i}");
// }
// $crmService->syncOpportunity('374720564');
$crmService->matchByName('Robot');
}
}
private function simulateMatchActivityStorm(int $teamId = 2, int $count = 100): void
{
$team = Team::find($teamId);
$config = $team->getCrmConfiguration();
$activities = Activity::query()
->where('crm_configuration_id', $config->getId())
->orderByDesc('id')
->limit($count)
->get();
$this->info("Dispatching {$activities->count()} MatchActivityCrmData jobs (portal={$config->getId()})");
foreach ($activities as $activity) {
MatchActivityCrmData::dispatch($activity->getId(), $config, true);
}
$this->info('Done. Watch logs and run jiminny:debug observeRateLimit to inspect cache state.');
}
private function simulateVerifyTaskStorm(int $teamId = 2, int $count = 100): void
{
$activities = Activity::query()
->where('team_id', $teamId)
->whereNotNull('crm_provider_id')
->orderByDesc('id')
->limit($count)
->get();
$this->info("Dispatching {$activities->count()} VerifyActivityCrmTaskJob jobs");
foreach ($activities as $activity) {
VerifyActivityCrmTaskJob::dispatch($activity->getId());
}
$this->info('Done.');
}
private function observeRateLimitCache(int $teamId = 2): void
{
$team = Team::find($teamId);
$config = $team->getCrmConfiguration();
$key = sprintf('hubspot:ratelimit:portal:%d', $config->getId());
$value = Redis::get($key);
$ttl = Redis::ttl($key);
$this->info("Redis key: {$key}");
$this->info('Value: ' . ($value ?? '(empty)'));
$this->info("TTL: {$ttl}s");
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5","depth":4,"bounds":{"left":0.54886967,"top":0.15003991,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"133","depth":4,"bounds":{"left":0.5588431,"top":0.15003991,"width":0.011968086,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"11","depth":4,"bounds":{"left":0.5728058,"top":0.15003991,"width":0.008976064,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5834442,"top":0.14844373,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.59075797,"top":0.14844373,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Support\\Facades\\Redis;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\Crm\\Delete\\VerifyActivityCrmTaskJob;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n UserPilotClient $userPilotClient\n ): void {\n // Choose ONE of the following to run, then comment out the others.\n // 1) Dispatch a storm of MatchActivityCrmData jobs against team 2\n $this->simulateMatchActivityStorm(teamId: 2, count: 100);\n\n // 2) Dispatch a storm of VerifyActivityCrmTaskJob jobs (simulates DeleteCrmEntityTrait fan-out)\n // $this->simulateVerifyTaskStorm(teamId: 2, count: 100);\n\n // 3) Inspect Redis circuit-breaker state for the team's HubSpot portal\n // $this->observeRateLimitCache(teamId: 2);\n\n // 4) Make 3 synchronous matchByName calls (foreground, hits API directly)\n // $this->rateLimit();\n exit(1);\n\n\n\n $report = AutomatedReport::find(71);\n $last = AutomatedReportResult::query()\n ->where('report_id', $report->getId())\n ->whereIn('status', [AutomatedReportResult::STATUS_DEFAULT, AutomatedReportResult::STATUS_FAILED])\n// ->where('reason', '!=', AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES)\n ->whereDate('created_at', CarbonImmutable::now()->toDateString())\n ->latest()\n ->first();\n\n $this->info(\"Last: {$last->getId()}\");\n\n exit(1);\n\n $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n\n $payload = [\n 'report_type' => 'ask_jiminny',\n 'frequency' => 'weekly',\n ];\n $userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);\n\n exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\n }\n\n private function rateLimit()\n {\n $team = Team::find(2);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n for ($i = 0 ; $i < 3; $i++) {\n// if ($i % 25 === 0) {\n// $this->info(\"Syncing opportunity {$i}\");\n $this->info(\"Matching contact {$i}\");\n// }\n// $crmService->syncOpportunity('374720564');\n $crmService->matchByName('Robot');\n }\n }\n\n private function simulateMatchActivityStorm(int $teamId = 2, int $count = 100): void\n {\n $team = Team::find($teamId);\n $config = $team->getCrmConfiguration();\n\n $activities = Activity::query()\n ->where('crm_configuration_id', $config->getId())\n ->orderByDesc('id')\n ->limit($count)\n ->get();\n\n $this->info(\"Dispatching {$activities->count()} MatchActivityCrmData jobs (portal={$config->getId()})\");\n\n foreach ($activities as $activity) {\n MatchActivityCrmData::dispatch($activity->getId(), $config, true);\n }\n\n $this->info('Done. Watch logs and run jiminny:debug observeRateLimit to inspect cache state.');\n }\n\n private function simulateVerifyTaskStorm(int $teamId = 2, int $count = 100): void\n {\n $activities = Activity::query()\n ->where('team_id', $teamId)\n ->whereNotNull('crm_provider_id')\n ->orderByDesc('id')\n ->limit($count)\n ->get();\n\n $this->info(\"Dispatching {$activities->count()} VerifyActivityCrmTaskJob jobs\");\n\n foreach ($activities as $activity) {\n VerifyActivityCrmTaskJob::dispatch($activity->getId());\n }\n\n $this->info('Done.');\n }\n\n private function observeRateLimitCache(int $teamId = 2): void\n {\n $team = Team::find($teamId);\n $config = $team->getCrmConfiguration();\n $key = sprintf('hubspot:ratelimit:portal:%d', $config->getId());\n\n $value = Redis::get($key);\n $ttl = Redis::ttl($key);\n\n $this->info(\"Redis key: {$key}\");\n $this->info('Value: ' . ($value ?? '(empty)'));\n $this->info(\"TTL: {$ttl}s\");\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Support\\Facades\\Redis;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\Crm\\Delete\\VerifyActivityCrmTaskJob;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n UserPilotClient $userPilotClient\n ): void {\n // Choose ONE of the following to run, then comment out the others.\n // 1) Dispatch a storm of MatchActivityCrmData jobs against team 2\n $this->simulateMatchActivityStorm(teamId: 2, count: 100);\n\n // 2) Dispatch a storm of VerifyActivityCrmTaskJob jobs (simulates DeleteCrmEntityTrait fan-out)\n // $this->simulateVerifyTaskStorm(teamId: 2, count: 100);\n\n // 3) Inspect Redis circuit-breaker state for the team's HubSpot portal\n // $this->observeRateLimitCache(teamId: 2);\n\n // 4) Make 3 synchronous matchByName calls (foreground, hits API directly)\n // $this->rateLimit();\n exit(1);\n\n\n\n $report = AutomatedReport::find(71);\n $last = AutomatedReportResult::query()\n ->where('report_id', $report->getId())\n ->whereIn('status', [AutomatedReportResult::STATUS_DEFAULT, AutomatedReportResult::STATUS_FAILED])\n// ->where('reason', '!=', AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES)\n ->whereDate('created_at', CarbonImmutable::now()->toDateString())\n ->latest()\n ->first();\n\n $this->info(\"Last: {$last->getId()}\");\n\n exit(1);\n\n $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n\n $payload = [\n 'report_type' => 'ask_jiminny',\n 'frequency' => 'weekly',\n ];\n $userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);\n\n exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\n }\n\n private function rateLimit()\n {\n $team = Team::find(2);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n for ($i = 0 ; $i < 3; $i++) {\n// if ($i % 25 === 0) {\n// $this->info(\"Syncing opportunity {$i}\");\n $this->info(\"Matching contact {$i}\");\n// }\n// $crmService->syncOpportunity('374720564');\n $crmService->matchByName('Robot');\n }\n }\n\n private function simulateMatchActivityStorm(int $teamId = 2, int $count = 100): void\n {\n $team = Team::find($teamId);\n $config = $team->getCrmConfiguration();\n\n $activities = Activity::query()\n ->where('crm_configuration_id', $config->getId())\n ->orderByDesc('id')\n ->limit($count)\n ->get();\n\n $this->info(\"Dispatching {$activities->count()} MatchActivityCrmData jobs (portal={$config->getId()})\");\n\n foreach ($activities as $activity) {\n MatchActivityCrmData::dispatch($activity->getId(), $config, true);\n }\n\n $this->info('Done. Watch logs and run jiminny:debug observeRateLimit to inspect cache state.');\n }\n\n private function simulateVerifyTaskStorm(int $teamId = 2, int $count = 100): void\n {\n $activities = Activity::query()\n ->where('team_id', $teamId)\n ->whereNotNull('crm_provider_id')\n ->orderByDesc('id')\n ->limit($count)\n ->get();\n\n $this->info(\"Dispatching {$activities->count()} VerifyActivityCrmTaskJob jobs\");\n\n foreach ($activities as $activity) {\n VerifyActivityCrmTaskJob::dispatch($activity->getId());\n }\n\n $this->info('Done.');\n }\n\n private function observeRateLimitCache(int $teamId = 2): void\n {\n $team = Team::find($teamId);\n $config = $team->getCrmConfiguration();\n $key = sprintf('hubspot:ratelimit:portal:%d', $config->getId());\n\n $value = Redis::get($key);\n $ttl = Redis::ttl($key);\n\n $this->info(\"Redis key: {$key}\");\n $this->info('Value: ' . ($value ?? '(empty)'));\n $this->info(\"TTL: {$ttl}s\");\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"lines":[{"char_start":273,"char_count":32,"bounds":{"left":0.61702126,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.61702126,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.61702126,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.61702126,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.61702126,"top":0.0,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.61702126,"top":0.0015961692,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.61702126,"top":0.01915403,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.61702126,"top":0.03671189,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.61702126,"top":0.054269753,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.61702126,"top":0.07182761,"width":0.38297874,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.61702126,"top":0.08938547,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.61702126,"top":0.10694334,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.61702126,"top":0.1245012,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.61702126,"top":0.14205906,"width":0.38297874,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.61702126,"top":0.15961692,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.61702126,"top":0.17717478,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.61702126,"top":0.19473264,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.61702126,"top":0.2122905,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.61702126,"top":0.22984837,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.61702126,"top":0.24740623,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.61702126,"top":0.26496407,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.61702126,"top":0.28252193,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3825721520770933767
|
3612178325362010539
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
5
133
11
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\Crm\Delete\VerifyActivityCrmTaskJob;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
UserPilotClient $userPilotClient
): void {
// Choose ONE of the following to run, then comment out the others.
// 1) Dispatch a storm of MatchActivityCrmData jobs against team 2
$this->simulateMatchActivityStorm(teamId: 2, count: 100);
// 2) Dispatch a storm of VerifyActivityCrmTaskJob jobs (simulates DeleteCrmEntityTrait fan-out)
// $this->simulateVerifyTaskStorm(teamId: 2, count: 100);
// 3) Inspect Redis circuit-breaker state for the team's HubSpot portal
// $this->observeRateLimitCache(teamId: 2);
// 4) Make 3 synchronous matchByName calls (foreground, hits API directly)
// $this->rateLimit();
exit(1);
$report = AutomatedReport::find(71);
$last = AutomatedReportResult::query()
->where('report_id', $report->getId())
->whereIn('status', [AutomatedReportResult::STATUS_DEFAULT, AutomatedReportResult::STATUS_FAILED])
// ->where('reason', '!=', AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES)
->whereDate('created_at', CarbonImmutable::now()->toDateString())
->latest()
->first();
$this->info("Last: {$last->getId()}");
exit(1);
$user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
$payload = [
'report_type' => 'ask_jiminny',
'frequency' => 'weekly',
];
$userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);
exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
private function rateLimit()
{
$team = Team::find(2);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
for ($i = 0 ; $i < 3; $i++) {
// if ($i % 25 === 0) {
// $this->info("Syncing opportunity {$i}");
$this->info("Matching contact {$i}");
// }
// $crmService->syncOpportunity('374720564');
$crmService->matchByName('Robot');
}
}
private function simulateMatchActivityStorm(int $teamId = 2, int $count = 100): void
{
$team = Team::find($teamId);
$config = $team->getCrmConfiguration();
$activities = Activity::query()
->where('crm_configuration_id', $config->getId())
->orderByDesc('id')
->limit($count)
->get();
$this->info("Dispatching {$activities->count()} MatchActivityCrmData jobs (portal={$config->getId()})");
foreach ($activities as $activity) {
MatchActivityCrmData::dispatch($activity->getId(), $config, true);
}
$this->info('Done. Watch logs and run jiminny:debug observeRateLimit to inspect cache state.');
}
private function simulateVerifyTaskStorm(int $teamId = 2, int $count = 100): void
{
$activities = Activity::query()
->where('team_id', $teamId)
->whereNotNull('crm_provider_id')
->orderByDesc('id')
->limit($count)
->get();
$this->info("Dispatching {$activities->count()} VerifyActivityCrmTaskJob jobs");
foreach ($activities as $activity) {
VerifyActivityCrmTaskJob::dispatch($activity->getId());
}
$this->info('Done.');
}
private function observeRateLimitCache(int $teamId = 2): void
{
$team = Team::find($teamId);
$config = $team->getCrmConfiguration();
$key = sprintf('hubspot:ratelimit:portal:%d', $config->getId());
$value = Redis::get($key);
$ttl = Redis::ttl($key);
$this->info("Redis key: {$key}");
$this->info('Value: ' . ($value ?? '(empty)'));
$this->info("TTL: {$ttl}s");
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
17915
|
NULL
|
NULL
|
NULL
|
|
17915
|
781
|
34
|
2026-05-11T10:41:26.151025+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496086151_m2.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/BadRequest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8912594269423517939
|
-8780801512462775350
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
PhpStormVIeWINavicarecodeLaravelKeractorTOOISWindowmelpFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitProiect vC) ErrorCateT SyncCrmEntitiesTrait.php© ErrorDetai© Filter.phpC FilterGrou(c) Corwardp,• Modelinte© NextPage© Paging.ph© PreviousP© PublicGdp© PublicObie© SimplePut© SimplePub© SimplePub© SimplePut(C) SimolePui© Standard:ApiException© Configuratio(C) HeaderSeled© ObiectSerialiMOwners› M Pioelines>M Products• M Provertiesm Quoted• M SchemasM Ticketc>D Timeline• M EventoM Silec• D Marketing,m WohhonkeMtocte@.aitianoreE.php_csM CHANGELOG.mO# composer.isoncomposer.lock-LCENSE.ohosoec.vmM.README.mdMhubspot-phov Msrc> D Endpointsv M Excentions4 RadRequect nhr4 Hubsnot=ycentiC InvalidAraument>M HtnTacts naccod. 12 120 minutes addlC) TrackAutomatedReportGeneratedevent.onp~© UserAutomatedReportsController.php© PlaybackController.phpC) CachedCrmServiceDecorator.ongJiminnyDeougcommana.ongT DeleteCrmEntityTrait.php© VerifyActivityCrmTaskJob.php© CheckAndRetryRemoteMatch.php© Job.php© BadRequest.php xC) Kernel.phg© PaginationState.php?phonamespace Sevenshores Hubspot Exceptions:class Badreouest extends Huspot Exceotion(c) HubSpot/Service.onpc) RateLimitExceptionlest.ongRateLimitException.phpCProviderkateLimiter.phg© PaginationConfig.phpReader Mode" suppont Dally • In 1h 15m100% L2• Mon 11 May 13:41:25HandleHubspotRateLimitTest v« console (PROD]* console (EUl& console (STAGINGI= laravel.log4 SF [jiminny@localhost]& HS_local [jiminny@localhost][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {w.19A"Date":["Thu,07 May 2026 14:21:15 GMT"],"Content-Type":["application/json;charset=utf-8"]."ranster-encoding"•L"chunked"!,"conneccion". Keep-alive"n"CF-Ray": ["9f80deb8db60dc3a-SOF"],"CF-Cache-Status":"DYNAMIC")"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")accept-encoding"],access-control-allow-credentials": "false")hserver-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfn:desc="9-80de8ercodc3a-TAD"'x-content-type-options": ["nosniff"]."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"]"Set-Cookie".[" cf bm=STUrtd0aXVrik50odaF6hZVYKhzTn0BidvMabeCtm0Y-1778163675-[IP_ADDRESS]-рT. ZaatDKxTae5zr8 2abBfWM00. ufZEXDZuHz2mBUFdzdo2aTHEs0)07-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f","endnoints"•!\"url\":\"https:|V/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn30%2BKVA3mFIJ2m7YRECDGS\"group\":\"cf-nel\",\"max_age\":604800}"],"success_fraction\":0.01,"repоrс_со " "cт-nel\"\"max_age\":604800}"],"Server":["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab"."trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}W Windsurf Teams 7:2 UTF-8 # 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17914
|
780
|
36
|
2026-05-11T10:41:26.150979+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496086150_m1.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/BadRequest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1579713784452094674
|
-8780890023316608054
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allED→Jiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay Ivanov3Aneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0::: AppsS Jira CloudToastGanala CalaSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:25Describe what you are looking forToastHomeMessagesAboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~NewToast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+Aa...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17912
|
780
|
35
|
2026-05-11T10:41:23.094096+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496083094_m1.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/BadRequest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Sync Changes...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7642997988936484088
|
-8132350251902047414
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Sync Changes
SlackFileEditViewGoHistoryWindowHelpDOCKER- ₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:22ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay Ivanov3Aneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
17910
|
NULL
|
NULL
|
NULL
|
|
17913
|
781
|
33
|
2026-05-11T10:41:23.090691+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496083090_m2.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/BadRequest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"bounds":{"left":0.5415558,"top":0.17318435,"width":0.034574468,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","depth":4,"bounds":{"left":0.11968085,"top":0.17158818,"width":0.47805852,"height":0.8076616},"on_screen":true,"lines":[{"char_start":7,"char_count":42,"bounds":{"left":0.11968085,"top":0.0,"width":0.10605053,"height":0.014365523}},{"char_start":50,"char_count":42,"bounds":{"left":0.11968085,"top":0.0,"width":0.10605053,"height":0.014365523}},{"char_start":92,"char_count":2,"bounds":{"left":0.11968085,"top":0.0,"width":0.0026595744,"height":0.014365523}},{"char_start":94,"char_count":1,"bounds":{"left":0.11968085,"top":0.0,"width":0.0026595744,"height":0.014365523}}],"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
-5958654610046146964
|
-8132355200912348342
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
PhpStormVIewINavicarecodeLaravelKeractorTOOISWindowFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitProiect vC) TrackAutomated ReportGeneratedzventonp© UserAutomatedReportsController.php© PlaybackController.php(C) Hubsnot/Service.ohnC) ErrorCateT SyncCrmEntitiesTrait.phpC) CachedCrmServiceDecorator.ong© JiminnyDebugCommand.phpT DeleteCrmEntityTrait.php© VerifyActivityCrmTaskJob.php© ErrorDetai© Filter.phpC FilterGrou(c) Corwardp.© CheckAndRetryRemoteMatch.php© Job.php© BadRequest.php x © Kernel.phgphp_ide_helper.php x C Pa© MatchCrmData.php© CrmObjectsResolver.php• Modelinte© NextPage© Paging.ph© PreviousP© PublicGdoC PublicObie© SimplePut© SimplePut© SimplePut© SimplePut© SimplePub© StandardEApiException© Configuratio(C) HeaderSeled© ObiectSeriali?ohonamesoace Sevenshores Hubsoot Excentions:class BadReauest extends HubsootExcentioniMOwners› M Pioelines>M Products• M PronertiesM Quoted• M SchemasM Ticketc>D Timeline• M EventoM Silec› D Marketing,m WohhonkeMtocte@.gitianoreE.php_csM+ CHANGELOG.mo# composer.isoncomposer.lockE LICENSEf phospec.vmM.README.mdMhubspot-phov Msrd> MEndpointsv MExcentions( RadRequect nhn4 Hubsnot=ycentiC InvalidAraument>M HttnMultilcTacts naccod. 12 120 minutes addl(c) HubSpot/Service.onpRateLimitException.php©)ProviderkateLimiter.pngReader Mode" suppont Dally • In 1h 15 m100% L2• Mon 11 May 13:41:22HandleHubspotRateLimitTest v« console (PROD]* console (EUl& console [STAGINGI= laravel.log4 SF [jiminny@localhost]& HS_local [jiminny@localhost][2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {w.19A"Date":["Thu,07 May 2026 14:21:15 GMT"],"Content-Type":["application/json;charset=utf-8"]."ranster-encoding"•L"chunked"!,"conneccion". Keep-alive"n"CF-Ray": ["9f80deb8db60dc3a-SOF"],"CF-Cache-Status":"DYNAMIC")"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")accept-encoding"],access-control-allow-credentials": "false")hserver-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfn:desc="9-80de8ercodc3a-TAD"x-content-type-options": ["nosniff"]."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"]"Set-Cookie".[" cf bm=STUrtd0aXVrik50odaF6hZVYKhzTn0BidvMabeCtm0Y-1778163675-[IP_ADDRESS]-рT. ZaatDKxTae5zr8 2abBfWM00. ufZEXDZuHz2mBUFdzdo2aTHEs0)07-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f","endnoints"•!\"url\":\"https:|V/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn30%2BKVA3mFIJ2m7YRECDGS\"group\":\"cf-nel\",\"max_age\":604800}"],"success_fraction\":0.01,"repоrс_со " "cт-nel\"\"max_age\":604800}"],"Server": ["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab".id": "c7ab8365-903f-46d4-9403-0e5b551e3545"}W Windsurf Teams 5:33 UTF-8 P 4 spaces ®...
|
17911
|
NULL
|
NULL
|
NULL
|
|
17910
|
780
|
34
|
2026-05-11T10:41:21.695789+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496081695_m1.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app, folder","depth":6,"on_screen":false,"role_description":"text"}]...
|
-5482213947665501964
|
-2310047280414997608
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17911
|
781
|
32
|
2026-05-11T10:41:21.689248+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496081689_m2.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"bounds":{"left":0.5415558,"top":0.17318435,"width":0.034574468,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","depth":4,"bounds":{"left":0.11968085,"top":0.17158818,"width":0.47805852,"height":0.8076616},"on_screen":true,"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
3558859946913695799
|
-8452886941114703088
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17909
|
781
|
31
|
2026-05-11T10:41:18.840345+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496078840_m2.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/BadRequest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"bounds":{"left":0.5415558,"top":0.17318435,"width":0.034574468,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","depth":4,"bounds":{"left":0.11968085,"top":0.17158818,"width":0.47805852,"height":0.8076616},"on_screen":true,"lines":[{"char_start":7,"char_count":42,"bounds":{"left":0.11968085,"top":0.0,"width":0.10605053,"height":0.014365523}},{"char_start":50,"char_count":42,"bounds":{"left":0.11968085,"top":0.0,"width":0.10605053,"height":0.014365523}},{"char_start":92,"char_count":2,"bounds":{"left":0.11968085,"top":0.0,"width":0.0026595744,"height":0.014365523}},{"char_start":94,"char_count":1,"bounds":{"left":0.11968085,"top":0.0,"width":0.0026595744,"height":0.014365523}}],"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.96276593,"top":0.07581804,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.61702126,"top":0.0726257,"width":0.38297874,"height":0.9066241},"on_screen":true,"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2761230881926117135
|
-3048906160892294806
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}...
|
17907
|
NULL
|
NULL
|
NULL
|
|
17908
|
780
|
33
|
2026-05-11T10:41:18.020961+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496078020_m1.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1684527879063584500
|
-8348266015821985344
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allED→Jiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0::: AppsS Jira CloudToastGanala CalaSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:17Describe what you are looking forToastHomeMessagesAboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~NewToast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+Aa...
|
17906
|
NULL
|
NULL
|
NULL
|
|
17907
|
781
|
30
|
2026-05-11T10:41:17.958548+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496077958_m2.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"bounds":{"left":0.5415558,"top":0.17318435,"width":0.034574468,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","depth":4,"bounds":{"left":0.11968085,"top":0.17158818,"width":0.47805852,"height":0.8076616},"on_screen":true,"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
-4444899959471851329
|
-8380828247565147376
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17906
|
780
|
32
|
2026-05-11T10:41:15.051806+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496075051_m1.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5641617897080429754
|
-8160223333407913180
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
SlackFileEditViewGoHistoryWindowHelpDOCKERO ₴1DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:14ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17905
|
781
|
29
|
2026-05-11T10:41:14.960283+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496074960_m2.jpg...
|
PhpStorm
|
faVsco.js – laravel.log
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1684527879063584500
|
-8348266015821985344
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
PhpStormVIewINavicareCodeKeractorTOOISWindowFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitProiect= custom.logT SyncCrmEntitiesTrait.php= nuospor-lournal-poll.log©) HandleHu<)> phpunit.xm© HandleHubspotRateLimit.phpos ttt.jsE oauth-private.keyE oauth-public.kev<?phpE storagenamesoace Sevenshores Hubsoot Excentions:E supervisord.pid"text-relav.isonuse..v w tests> Featurelintearation9O1lclass HubspotException extends Exception• Servicesv 7UniResnonse lnul1Actionsprotected Sresponse;N ComoonentN ConfiaurationReturns: Response nullM consoleiM Contractspublic function getResponseOf...}h DomainIDTOpublic static function create(RequestException SquzzleException): self{...}D EnumsD Eventsprotected static function sanitizeResponseMessage(string Smessage): strinaf...}D Exceptions)mCrm.o SmailA ctivityimnortEydw HandlerTlest.pnp© RateLimitExceptionTesCo fixturesC GuardsW Helpersm) HttoIntearationsalinteractionsaHobs> Activitv> M AiAutomation> M Audicv AutomatedReportsc CreateResultsTest.© RequestGenerateA:C) RequestGenerateR,( SendRenortEynirindC) SendRenort lohTec( SendRenortMail.lohC SendRenortNotGen)mCnlondar)MCrmM nonlDicke• MMailbayTacts naccod. 12 (28 minutes aaolS0 hll"suppont Dally • In 1h 15m100% C47. • Mon 11 May 13:41:14HandleHubspotRateLimitTest v= custom.log= laravel.log X 4 SF [jiminny@localhost]& HS_local [jiminny@localhost]« console (PROD]* console (EUlA console [STAGING]Q- Received 429 from API |X Cc W .*C) TrackAutomated ReportGeneratedzventonp© UserAutomatedReportsController.php© PlaybackController.php(C) Hubsnot/Service.ohn© HubSpot/Service.phpC) CachedCrmServiceDecorator.ong© JiminnyDebugCommand.phpTDeleteCrmEntityTrait.php© VerifyActivityCrmTaskJob.php© RateLimitExceptionTest.php© CheckAndRetryRemoteMatch.php© MatchActivityCrmData.php © Job.php©CrmActivityService.php© RateLimitException.phpBadkequest.pngHubspotexception.php xC) Kernel.phpphp_ide_helper.php© PaginationState.php© MatchCrmData.php© CrmObjectsResolver.phpReader Modeio 4 spaces ©...
|
17903
|
NULL
|
NULL
|
NULL
|
|
17904
|
780
|
31
|
2026-05-11T10:41:12.033151+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496072033_m1.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV ( SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:11ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
NULL
|
-7217249381493529727
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV ( SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:11ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
17901
|
NULL
|
NULL
|
NULL
|
|
17903
|
781
|
28
|
2026-05-11T10:41:11.898921+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496071898_m2.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/5
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"bounds":{"left":0.5415558,"top":0.17318435,"width":0.034574468,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","depth":4,"bounds":{"left":0.11968085,"top":0.17158818,"width":0.47805852,"height":0.8076616},"on_screen":true,"lines":[{"char_start":7,"char_count":42,"bounds":{"left":0.11968085,"top":0.0,"width":0.10605053,"height":0.014365523}},{"char_start":50,"char_count":15,"bounds":{"left":0.11968085,"top":0.0,"width":0.010305851,"height":0.014365523}},{"char_start":65,"char_count":43,"bounds":{"left":0.1299867,"top":0.0,"width":0.0026595744,"height":0.014365523}},{"char_start":108,"char_count":30,"bounds":{"left":0.1299867,"top":0.0,"width":0.0076462766,"height":0.014365523}},{"char_start":139,"char_count":41,"bounds":{"left":0.11968085,"top":0.0,"width":0.10372341,"height":0.014365523}},{"char_start":180,"char_count":2,"bounds":{"left":0.11968085,"top":0.012769354,"width":0.0026595744,"height":0.014365523}},{"char_start":182,"char_count":30,"bounds":{"left":0.11968085,"top":0.030327214,"width":0.0026595744,"height":0.014365523}},{"char_start":212,"char_count":25,"bounds":{"left":0.11968085,"top":0.055067837,"width":0.06216755,"height":0.014365523}},{"char_start":238,"char_count":8,"bounds":{"left":0.11968085,"top":0.090183556,"width":0.0026595744,"height":0.014365523}},{"char_start":246,"char_count":29,"bounds":{"left":0.11968085,"top":0.090183556,"width":0.0026595744,"height":0.014365523}},{"char_start":275,"char_count":8,"bounds":{"left":0.11968085,"top":0.090183556,"width":0.0026595744,"height":0.014365523}},{"char_start":283,"char_count":34,"bounds":{"left":0.11968085,"top":0.1292897,"width":0.08543883,"height":0.014365523}},{"char_start":317,"char_count":6,"bounds":{"left":0.20511968,"top":0.1292897,"width":0.0026595744,"height":0.014365523}},{"char_start":323,"char_count":32,"bounds":{"left":0.20511968,"top":0.1292897,"width":0.0026595744,"height":0.014365523}},{"char_start":355,"char_count":6,"bounds":{"left":0.20511968,"top":0.1292897,"width":0.012965426,"height":0.014365523}},{"char_start":362,"char_count":75,"bounds":{"left":0.11968085,"top":0.16440542,"width":0.19182181,"height":0.014365523}},{"char_start":437,"char_count":6,"bounds":{"left":0.31150267,"top":0.16440542,"width":0.0026595744,"height":0.014365523}},{"char_start":443,"char_count":25,"bounds":{"left":0.31150267,"top":0.16440542,"width":0.0026595744,"height":0.014365523}},{"char_start":468,"char_count":77,"bounds":{"left":0.31150267,"top":0.16440542,"width":0.0026595744,"height":0.014365523}},{"char_start":545,"char_count":41,"bounds":{"left":0.31150267,"top":0.16440542,"width":0.0026595744,"height":0.014365523}},{"char_start":586,"char_count":29,"bounds":{"left":0.31150267,"top":0.16440542,"width":0.0026595744,"height":0.014365523}},{"char_start":615,"char_count":11,"bounds":{"left":0.31150267,"top":0.16440542,"width":0.0026595744,"height":0.014365523}},{"char_start":627,"char_count":264,"bounds":{"left":0.11968085,"top":0.16440542,"width":0.19448139,"height":0.06703911}}],"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nuse Exception;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Psr7\\Response;\n\nclass HubspotException extends Exception\n{\n /** @var null|Response */\n protected $response;\n\n /**\n * @return null|Response\n */\n public function getResponse()\n {\n return $this->response;\n }\n\n public static function create(RequestException $guzzleException): self\n {\n $e = new static(\n static::sanitizeResponseMessage($guzzleException->getMessage()),\n $guzzleException->getCode(),\n $guzzleException\n );\n\n $e->response = $guzzleException->getResponse();\n\n return $e;\n }\n\n protected static function sanitizeResponseMessage(string $message): string\n {\n return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"bounds":{"left":0.60206115,"top":0.08060654,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"bounds":{"left":0.6146942,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Received 429 from API","depth":4,"bounds":{"left":0.6256649,"top":0.07980846,"width":0.0631649,"height":0.015961692},"on_screen":true,"value":"Received 429 from API","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.6978058,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"bounds":{"left":0.7077792,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"bounds":{"left":0.71642286,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"bounds":{"left":0.7250665,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1/5","depth":4,"bounds":{"left":0.7386968,"top":0.079010375,"width":0.025598405,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"bounds":{"left":0.7642952,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"bounds":{"left":0.77293885,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"bounds":{"left":0.7815825,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Window, Multiple Cursors","depth":4,"bounds":{"left":0.79022604,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Click to highlight","depth":4,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":4,"bounds":{"left":0.97539896,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
3403966717484810055
|
-8380825052081167608
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
class HubspotException extends Exception
{
/** @var null|Response */
protected $response;
/**
* @return null|Response
*/
public function getResponse()
{
return $this->response;
}
public static function create(RequestException $guzzleException): self
{
$e = new static(
static::sanitizeResponseMessage($guzzleException->getMessage()),
$guzzleException->getCode(),
$guzzleException
);
$e->response = $guzzleException->getResponse();
return $e;
}
protected static function sanitizeResponseMessage(string $message): string
{
return preg_replace('/(hapikey|access_token)=[a-z0-9-]+/i', '$1=***', $message);
}
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/5
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17901
|
780
|
30
|
2026-05-11T10:41:04.192179+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496064192_m1.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER-₴81DEV SlackFileEditViewGoHistoryWindowHelpDOCKER-₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:03ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
NULL
|
6500515954492923307
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER-₴81DEV SlackFileEditViewGoHistoryWindowHelpDOCKER-₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More(allSupport Daily • in 1h 19 m100% <78• Mon 11 May 13:41:03ED→Describe what you are looking forJiminny ...Toast# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...HomeMessages^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0AboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changed::: AppsS Jira CloudMessage ToastToast+AaGanala CalaNew...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17902
|
781
|
27
|
2026-05-11T10:41:04.180532+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496064180_m2.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ClaudecaltVIewWindow0, Chat:= Cowork" Coae+ Ne ClaudecaltVIewWindow0, Chat:= Cowork" Coae+ New chatã Projectso0 Arutacts₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectHubspot sadkequest headers debuggingScreenpipe svnc scriot tailing after receiMonthly expense trackingExporting transaction data from Notion t® How much have I spent for groc...Code dift reviewHubSpot rate limit imolementation strateScreenpipe retention policy code locatioViewing retention policy in screenpipeclean snot x video recoraing terminaticHubSpot rate limit handling with executelUntitledaScreen oine. Is there ability.SMB mount access inconsistency betweWhat is the best switch I can..Last swimming outing with DaniDefinition of incarcerated• suppont Dally • In 1h 15m100% 1Mon 11 May 13:41:03Hubspot BadRequest headers debuggingn ue sudsdotrar suk, backequest comes urougn as an Aot xcention.r exdoses ueresponse headers via getResponseHeaders() :use Hubspot cllent crm contacts Apltxception:try ($response = $hubspot->crm()->contacts()->basicApi()->create($input);cauch Aplexception sesstatus= $e->getCodeO:sbody= $e->getResponseBody();$headers = $e->getResponseHeaders();400raw JSON string with the erro// array of headersLog: :warning('HubSpot BadRequest', [= sstatus.' body'=> $body,'headers' = $headers,// useful ones for debugging / rate limits:'correlation id' => $headers['X-HubSpot-Correlation-Id'] ?? null.'daily_remaining' => $headers['X-HubSpot-RateLimit-Daily-Remaining'] ?? null,'secondly remaining => $headersl'X-HubSpot-RateLimit-Secondly-Remaining'J ??I);Note getResponseHeaders() returns an associative array where values may be arrays (oneentry per header occurrence), so for safety:ScorrelationId = is arrav(Sheadersf'X-HubSpot-Correlation-Id'] 22 null)? Sheadersl'X-HubSpot-Correlation-1d'JLoJ: ($headers['X-HubSpot-Correlation-Id'] ?? null);The X-HubSpot-Correlation-Id is the one to grab if you need to open a ticket with HubSpot- they 'll ask for itIf you're using Guzzle directly instead of the SDK, it's $e->getResponse () ->getHeaders() ona RequestExcention/ Chientsxcention.t/Service.phpest.ongReader Mode= custom.logReceived 429 from APICc W .*emote_search": true, "set_configuration":2, "old_state": {"lead_id":null, "contact_id" :null, "account_id":26, "opportunity_id":22, "stage_id":89}} factivities", "entityld":615092, "collectionKey": "activities-for-update-priority", "withPriority":true} {"correlation_id":"fObecb3b-1f4f-4fb3-a31cipants": [{"id":1004102, "user_id":null, "contact_id":null,"lead_id":null},{"id":1004103,"user_id":89.contact_id":null, "lead_id":null}]} {"cor":"hubspot"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"}p": "hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449"', "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"},"identifier":"[EMAIL]"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id":"8e45b868-2eb5-42f8-a91e-229" "reason":" [404] Client erroprospect caca luentltleest"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id":"8e4StIcer":10,"poL1cy:null, "reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/00zecrs/concact/searchresulced in a 42y 100 Many Kequest\"correlationid)":\"019e168a-5 (truncated...)5/0"job_class": "Jiminny|\Jobs|\Crm\ \MatchActivityCrmData", "attempts":1, "retry_after":10, "delay":14} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-90emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-ba1ontact_id":null, "lead_id":null}l} f"corNNWrite a message..Opus 4.7 Adaptive vdentatsten.mkollay.nkolloycrGiminny.com"ooccellataion1.8580/kh2-bilef-Zbae-haiZeChasFhseskahltoace TW•8e215h868-2eh5-WH8-a9le-2295Mlemethod {"identifier_type":"ejob_class":"Jiminny|\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10, "delay""•"cpanchahle-nhcenven-undatp"l "entitvld"•,1dactivities", "entityId":614382, "collectionkey":"activities-for-update-pricipants": [{"id":1002632, "user_id":null, "contact_id":null,"lead_id":rcontact_id" :null, "lead_id":nullfl} {"corrrelation_id":"78f847cf-6495-4054-b3d4-e179a133bd42", "trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}-p"': "hubspot", "crm_owner": 148, "teamdencltler":"n1kolay.n1ko Lovo1m1nny10b class". "JaminnyJobs urm Macchaciv1cyurmuar."opportunity id":22."staqe_id":89}} {'":"searchable-observer-update"."entitvid":614581- *"Co"trace_1d": "8e450868-22b5-42f8-a97cipants":"1d": 1002":nulur *"conn"*"hubspot""crm owmethod "identifierlK Lukas. ProClaude is Al and can make mistakes. Please double-check responses....
|
NULL
|
-1020220995584945994
|
NULL
|
click
|
ocr
|
NULL
|
ClaudecaltVIewWindow0, Chat:= Cowork" Coae+ Ne ClaudecaltVIewWindow0, Chat:= Cowork" Coae+ New chatã Projectso0 Arutacts₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectHubspot sadkequest headers debuggingScreenpipe svnc scriot tailing after receiMonthly expense trackingExporting transaction data from Notion t® How much have I spent for groc...Code dift reviewHubSpot rate limit imolementation strateScreenpipe retention policy code locatioViewing retention policy in screenpipeclean snot x video recoraing terminaticHubSpot rate limit handling with executelUntitledaScreen oine. Is there ability.SMB mount access inconsistency betweWhat is the best switch I can..Last swimming outing with DaniDefinition of incarcerated• suppont Dally • In 1h 15m100% 1Mon 11 May 13:41:03Hubspot BadRequest headers debuggingn ue sudsdotrar suk, backequest comes urougn as an Aot xcention.r exdoses ueresponse headers via getResponseHeaders() :use Hubspot cllent crm contacts Apltxception:try ($response = $hubspot->crm()->contacts()->basicApi()->create($input);cauch Aplexception sesstatus= $e->getCodeO:sbody= $e->getResponseBody();$headers = $e->getResponseHeaders();400raw JSON string with the erro// array of headersLog: :warning('HubSpot BadRequest', [= sstatus.' body'=> $body,'headers' = $headers,// useful ones for debugging / rate limits:'correlation id' => $headers['X-HubSpot-Correlation-Id'] ?? null.'daily_remaining' => $headers['X-HubSpot-RateLimit-Daily-Remaining'] ?? null,'secondly remaining => $headersl'X-HubSpot-RateLimit-Secondly-Remaining'J ??I);Note getResponseHeaders() returns an associative array where values may be arrays (oneentry per header occurrence), so for safety:ScorrelationId = is arrav(Sheadersf'X-HubSpot-Correlation-Id'] 22 null)? Sheadersl'X-HubSpot-Correlation-1d'JLoJ: ($headers['X-HubSpot-Correlation-Id'] ?? null);The X-HubSpot-Correlation-Id is the one to grab if you need to open a ticket with HubSpot- they 'll ask for itIf you're using Guzzle directly instead of the SDK, it's $e->getResponse () ->getHeaders() ona RequestExcention/ Chientsxcention.t/Service.phpest.ongReader Mode= custom.logReceived 429 from APICc W .*emote_search": true, "set_configuration":2, "old_state": {"lead_id":null, "contact_id" :null, "account_id":26, "opportunity_id":22, "stage_id":89}} factivities", "entityld":615092, "collectionKey": "activities-for-update-priority", "withPriority":true} {"correlation_id":"fObecb3b-1f4f-4fb3-a31cipants": [{"id":1004102, "user_id":null, "contact_id":null,"lead_id":null},{"id":1004103,"user_id":89.contact_id":null, "lead_id":null}]} {"cor":"hubspot"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"}p": "hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449"', "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"},"identifier":"[EMAIL]"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id":"8e45b868-2eb5-42f8-a91e-229" "reason":" [404] Client erroprospect caca luentltleest"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id":"8e4StIcer":10,"poL1cy:null, "reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/00zecrs/concact/searchresulced in a 42y 100 Many Kequest\"correlationid)":\"019e168a-5 (truncated...)5/0"job_class": "Jiminny|\Jobs|\Crm\ \MatchActivityCrmData", "attempts":1, "retry_after":10, "delay":14} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-90emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-ba1ontact_id":null, "lead_id":null}l} f"corNNWrite a message..Opus 4.7 Adaptive vdentatsten.mkollay.nkolloycrGiminny.com"ooccellataion1.8580/kh2-bilef-Zbae-haiZeChasFhseskahltoace TW•8e215h868-2eh5-WH8-a9le-2295Mlemethod {"identifier_type":"ejob_class":"Jiminny|\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10, "delay""•"cpanchahle-nhcenven-undatp"l "entitvld"•,1dactivities", "entityId":614382, "collectionkey":"activities-for-update-pricipants": [{"id":1002632, "user_id":null, "contact_id":null,"lead_id":rcontact_id" :null, "lead_id":nullfl} {"corrrelation_id":"78f847cf-6495-4054-b3d4-e179a133bd42", "trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}-p"': "hubspot", "crm_owner": 148, "teamdencltler":"n1kolay.n1ko Lovo1m1nny10b class". "JaminnyJobs urm Macchaciv1cyurmuar."opportunity id":22."staqe_id":89}} {'":"searchable-observer-update"."entitvid":614581- *"Co"trace_1d": "8e450868-22b5-42f8-a97cipants":"1d": 1002":nulur *"conn"*"hubspot""crm owmethod "identifierlK Lukas. ProClaude is Al and can make mistakes. Please double-check responses....
|
17899
|
NULL
|
NULL
|
NULL
|
|
17900
|
780
|
29
|
2026-05-11T10:40:52.879046+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496052879_m1.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKERO ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKERO ₴1DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More> 0.ED→Jiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0::: AppsS Jira CloudToastGanala CalaSupport Daily • in 1h 20 m100% <78• Mon 11 May 13:40:52Describe what you are looking forToastHomeMessagesAboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~NewToast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+Aa...
|
NULL
|
-6341810313621429629
|
NULL
|
idle
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKERO ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKERO ₴1DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More> 0.ED→Jiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0::: AppsS Jira CloudToastGanala CalaSupport Daily • in 1h 20 m100% <78• Mon 11 May 13:40:52Describe what you are looking forToastHomeMessagesAboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~NewToast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+Aa...
|
17897
|
NULL
|
NULL
|
NULL
|
|
17899
|
781
|
26
|
2026-05-11T10:40:41.376837+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496041376_m2.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
calVIewWindow0, Chat= Cowork+ New chatã Projectso calVIewWindow0, Chat= Cowork+ New chatã Projectso0 Arutacts₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectHubspot sadkequest headers debuggingScreenpipe svnc scriot tailing after receiMonthly expense trackingExporting transaction data from Notion t® How much have I spent for groc...Code dift reviewHubSpot rate limit imolementation strateScreenpipe retention policy code locatioViewing retention policy in screenpipeclean snot x video recoraing terminatiorHubSpot rate limit handling with executelUntitledg Screen pipe. Is there ability..SMB mount access inconsistency betweWhat is the best switch I can..rermission deniea on screenpipe volumeLast swimming outing with DanDefinition of incarceratedSupport Daily - in 1h 20m100% 1Mon 11 May 13:40:41Hubspot BadRequest headers debuggingt/Service.phpest.ong© RateLimitException.php© CrmObjectsResolver.phpIhave BadRequest in HUbspot how to get headersIdentified HubSpot API exception handling for retrieving response headers›In the HubSpot PHP SDK, BadRequest comes through as an ApiException. It exposes theresponse headers via getResponseHeaders() :use HubSpot\Client\Crm\Contacts\ApiException;tryt$response = $hubspot->crm()->contacts()->basicApi()->create($input);} catch (ApiException $e) {sstatus=se->cetlodeo:400$body= $e->getResponseBody();// raw JSON string with the errorSheaders = Se->getResponseHeaders;/ array of headersLog: :warning('HubSpot BadRequest', [status= sstatus"hodv= Shodv.'headers' => $headers,// useful ones for debugging / rate limits:'correlation_id' => $headers['X-HubSpot-Correlation-Id'] ?? null,'daily remaining' => Sheadersf'X-HubSpot-RateLimit-Dailv-Remaining'] 2? null'secondly remaining' => $headers['X-HubSpot-RateLimit-Secondlv-Remaining'1 22]):Note getResponseHeaders returns an associative array where values may be arrays (oneentry per header occurrence), so for safety:$correlationId = is array($headers['X-HubSpot-Correlation-Id'] ?? null)?Sheaders"X-HubSoot-Correlation-1d'101: ($headers['X-HubSpot-Correlation-Id'] ?? null);The X-HubSpot-Correlation-Id is the one to grab if you need to open a ticket with Hub*Write a message…Reader Mode= custom.logE laravel.logxReceived 429 from APICc W .*X558emote_search":true, "set_configuration":2, "old_state" : {"Lead_id":null, "contact_id":null, "account_id":26, "opportunity_id":22, "stage_id":89}} €*activities", "entityld":615092, "collectionKey": "activities-for-update-priority", "withPriority":true} {"correlation_id":"fObecb3b-1f4f-4fb3-a31cipants": [{"id":1004102, "user_id":null, "contact_id":null,"lead_id":null},{"id":1004103,"user_id":89contact_id":null, "lead_id":null}]} {"cor":"hubspot"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"}p": "hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449"', "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"},"identifier":"[EMAIL]"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id":"8e45b868-2eb5-42f8-a91e-229" "reason":" [404] Client erroprospect caca luentltleУрес епаль, поепешелс пикосау.лико сомодшалпу,сош а сомешастог дао торесоро-итат-4тоз-аб4-7050т02ае44Yest"r ""correlacion 10: T0becb5d-1t4t-4t5-a511-Y056t0zae447, "Crace 10": 80450Icer":10,"poL1cy:null, "reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/00zecrs/concact/searchresulced in a 42y 100 Many Kequest\"correlationid)":\"019e168a-5 (truncated...)5/0"job_class": "Jiminny| \Jobs|\Crm\ \MatchActivityCrmData", "attempts":1, "retry_after":10, "delay":14} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-90emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-ba1ontact_id":null, "Lead_id":null}l} f"carmethod {"identifier_type":"ejob_class":"Jiminny|\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10, "delay""•"cpanchahle-nhcenven-undatp"l "entitvld"•,1dactivities", "entityId":614382, "collectionkey" :"acipants": [{"id":1002632, "user_id":null, "contact_id":null,"lead_id":nrrelation_id":"78f847cf-6495-4054-b3d4-e179a133bd42", "trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}p": "hubspot" "crm_owner":148, "teamdencltler":"n1kolay.n1ko Lovd 1m1nn10b class". "JaminnyJobs urm Macchaciv1cyurmuar.":"searchable-observer-update"."entitvid":614581- *"Cocipants":"1d": 1002contact_id" :null, "lead_id":nullfl} {"cor"opportunity id":22."staqe_id":89}} {'"trace_1d": "8e450868-22b5-42f8-a97":nulur *"conOpus 4.7 Adaptive vn"""hubspot"method "identifierlK Lukas. ProClaude is Al and can make mistakes. Please double-check responses....
|
NULL
|
-709141796623221900
|
NULL
|
visual_change
|
ocr
|
NULL
|
calVIewWindow0, Chat= Cowork+ New chatã Projectso calVIewWindow0, Chat= Cowork+ New chatã Projectso0 Arutacts₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectHubspot sadkequest headers debuggingScreenpipe svnc scriot tailing after receiMonthly expense trackingExporting transaction data from Notion t® How much have I spent for groc...Code dift reviewHubSpot rate limit imolementation strateScreenpipe retention policy code locatioViewing retention policy in screenpipeclean snot x video recoraing terminatiorHubSpot rate limit handling with executelUntitledg Screen pipe. Is there ability..SMB mount access inconsistency betweWhat is the best switch I can..rermission deniea on screenpipe volumeLast swimming outing with DanDefinition of incarceratedSupport Daily - in 1h 20m100% 1Mon 11 May 13:40:41Hubspot BadRequest headers debuggingt/Service.phpest.ong© RateLimitException.php© CrmObjectsResolver.phpIhave BadRequest in HUbspot how to get headersIdentified HubSpot API exception handling for retrieving response headers›In the HubSpot PHP SDK, BadRequest comes through as an ApiException. It exposes theresponse headers via getResponseHeaders() :use HubSpot\Client\Crm\Contacts\ApiException;tryt$response = $hubspot->crm()->contacts()->basicApi()->create($input);} catch (ApiException $e) {sstatus=se->cetlodeo:400$body= $e->getResponseBody();// raw JSON string with the errorSheaders = Se->getResponseHeaders;/ array of headersLog: :warning('HubSpot BadRequest', [status= sstatus"hodv= Shodv.'headers' => $headers,// useful ones for debugging / rate limits:'correlation_id' => $headers['X-HubSpot-Correlation-Id'] ?? null,'daily remaining' => Sheadersf'X-HubSpot-RateLimit-Dailv-Remaining'] 2? null'secondly remaining' => $headers['X-HubSpot-RateLimit-Secondlv-Remaining'1 22]):Note getResponseHeaders returns an associative array where values may be arrays (oneentry per header occurrence), so for safety:$correlationId = is array($headers['X-HubSpot-Correlation-Id'] ?? null)?Sheaders"X-HubSoot-Correlation-1d'101: ($headers['X-HubSpot-Correlation-Id'] ?? null);The X-HubSpot-Correlation-Id is the one to grab if you need to open a ticket with Hub*Write a message…Reader Mode= custom.logE laravel.logxReceived 429 from APICc W .*X558emote_search":true, "set_configuration":2, "old_state" : {"Lead_id":null, "contact_id":null, "account_id":26, "opportunity_id":22, "stage_id":89}} €*activities", "entityld":615092, "collectionKey": "activities-for-update-priority", "withPriority":true} {"correlation_id":"fObecb3b-1f4f-4fb3-a31cipants": [{"id":1004102, "user_id":null, "contact_id":null,"lead_id":null},{"id":1004103,"user_id":89contact_id":null, "lead_id":null}]} {"cor":"hubspot"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"}p": "hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449"', "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"},"identifier":"[EMAIL]"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id":"8e45b868-2eb5-42f8-a91e-229" "reason":" [404] Client erroprospect caca luentltleУрес епаль, поепешелс пикосау.лико сомодшалпу,сош а сомешастог дао торесоро-итат-4тоз-аб4-7050т02ае44Yest"r ""correlacion 10: T0becb5d-1t4t-4t5-a511-Y056t0zae447, "Crace 10": 80450Icer":10,"poL1cy:null, "reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/00zecrs/concact/searchresulced in a 42y 100 Many Kequest\"correlationid)":\"019e168a-5 (truncated...)5/0"job_class": "Jiminny| \Jobs|\Crm\ \MatchActivityCrmData", "attempts":1, "retry_after":10, "delay":14} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-90emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-ba1ontact_id":null, "Lead_id":null}l} f"carmethod {"identifier_type":"ejob_class":"Jiminny|\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10, "delay""•"cpanchahle-nhcenven-undatp"l "entitvld"•,1dactivities", "entityId":614382, "collectionkey" :"acipants": [{"id":1002632, "user_id":null, "contact_id":null,"lead_id":nrrelation_id":"78f847cf-6495-4054-b3d4-e179a133bd42", "trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}p": "hubspot" "crm_owner":148, "teamdencltler":"n1kolay.n1ko Lovd 1m1nn10b class". "JaminnyJobs urm Macchaciv1cyurmuar.":"searchable-observer-update"."entitvid":614581- *"Cocipants":"1d": 1002contact_id" :null, "lead_id":nullfl} {"cor"opportunity id":22."staqe_id":89}} {'"trace_1d": "8e450868-22b5-42f8-a97":nulur *"conOpus 4.7 Adaptive vn"""hubspot"method "identifierlK Lukas. ProClaude is Al and can make mistakes. Please double-check responses....
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17898
|
781
|
25
|
2026-05-11T10:40:38.328760+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496038328_m2.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ClaudtcalVIewWindowHubspot BadRequest headers debu ClaudtcalVIewWindowHubspot BadRequest headers debuggingSupport Daily - in 1h 20 m100% 1Mon 11 May 13:40:38Q, Chat= Cowork" Coae+ New chatã Projectso0 Arutacis₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectHubspot sadkequest headers debuggingScreenpipe svnc scriot tailing after receiMonthly expense trackingEynorting transaction data from Notion@ How much have I spent for groc…Code dift reviewHubSpot rate limit imolementation strateScreenoine retention policv code locaticViewing retention policy in screenpipeclean snot x video recoraing terminatiorHubSpot rate limit handling with executeUntitleda Screen oine. Is there ability.SMB mount access inconsistency betwea What is the hect switch Icanrermission deniea on screenpipe volumeScreenpipe sync database attachment eLast swimming outing with DanThave BadRequest in HUbspot how to get headerst/Service.onpest.ong© RateLimitException.php© CrmObjectsResolver.phpReader Mode= custom.logIdentified HubSpot API exception handling for retrieving response headers ›In the HubSpot PHP SDK. BadRequest comes through asan ApiExcention. It exposes theresponse headers via getResponseHeaders:Received 429 from APICc W.*emote_search": true, "set_configuration":2, "old_state":{"lead_id" :null, "contact_id":null, "account_id":26,"opportunity_id":22,"stage_id":89}} {*activities","entityId":615092,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f0becb3b-1f4f-4fb3-a31cinants"•"id":1004102."usen id".null"contact id".null."lead_ id".null?."id":1004103 "usen id":89"contact id".null "lead id".nulle «"con":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}use HubSpot Client\Crm Contacts ApiException:try ?§response = $hubspot->crm->contacts->basicApi->create($input):}catch (ApiException $e) {sstatus=se->cetlodeo:400sbodySheaders = SeSe->getResoonseBodvo:I/ raw JSON string with the erronпяшелецВанениько сауинКО сОмоуСОIо са сOLOTOUAсDOD-1144 US-SY0S0TUZaE44Yn UaCe LUN O8450006-[CREDIT_CARD]" "noacon"."(4Azl Cljent ennoprospect caca luentltleУрес епаль, поепешелс пикосау.лико сомодшалпу,сош а сомешастог дао торесоро-итат-4тоз-аб4-7050т02ае44Yest"} {"correlation id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449" "trace id":"8e45bIcer":10,"pol1cy:null,"reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/0bzecrs/concact/ searchresulced in a 42y 100 Many kequest5/0"Job_cLass": "Jamanny (Jobs \\Crm\ \MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9€emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-ba1ontact_ id":null. "lead_id":null}l} {"coractivities","entityId":614382,"collectionKey":"activities-for-update-pricontact idi.null "lead idi.nulllil Siconrrelation_id":"78f847cf-6495-4054-b3d4-e179a133bd42" "trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}dencitler": "n1kolay.n1ko Lovo 1m1nnyTATEESSTATITTILBACO:FDWNAITUANLTTKTATTTBAYEE ETATATN ATAS ITATAT A : EТ/Т:: ПТЕТУЕИT10b class". "JaminnyJobs urm Macchacciv1cyurmuar.cipants":"1d": 100"opportunity id":22."staqe_id":89}} {'"trace_1d": "8e450868-22b5-42f8-a97":nulur *"conWrite a message…Opus 4.7 Adaptivemethod "identifierlK Lukas. ProCaudo ic Aland can mako mictakac Plesce double-chock recnoncod...
|
NULL
|
-8356610616395653030
|
NULL
|
visual_change
|
ocr
|
NULL
|
ClaudtcalVIewWindowHubspot BadRequest headers debu ClaudtcalVIewWindowHubspot BadRequest headers debuggingSupport Daily - in 1h 20 m100% 1Mon 11 May 13:40:38Q, Chat= Cowork" Coae+ New chatã Projectso0 Arutacis₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectHubspot sadkequest headers debuggingScreenpipe svnc scriot tailing after receiMonthly expense trackingEynorting transaction data from Notion@ How much have I spent for groc…Code dift reviewHubSpot rate limit imolementation strateScreenoine retention policv code locaticViewing retention policy in screenpipeclean snot x video recoraing terminatiorHubSpot rate limit handling with executeUntitleda Screen oine. Is there ability.SMB mount access inconsistency betwea What is the hect switch Icanrermission deniea on screenpipe volumeScreenpipe sync database attachment eLast swimming outing with DanThave BadRequest in HUbspot how to get headerst/Service.onpest.ong© RateLimitException.php© CrmObjectsResolver.phpReader Mode= custom.logIdentified HubSpot API exception handling for retrieving response headers ›In the HubSpot PHP SDK. BadRequest comes through asan ApiExcention. It exposes theresponse headers via getResponseHeaders:Received 429 from APICc W.*emote_search": true, "set_configuration":2, "old_state":{"lead_id" :null, "contact_id":null, "account_id":26,"opportunity_id":22,"stage_id":89}} {*activities","entityId":615092,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f0becb3b-1f4f-4fb3-a31cinants"•"id":1004102."usen id".null"contact id".null."lead_ id".null?."id":1004103 "usen id":89"contact id".null "lead id".nulle «"con":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}use HubSpot Client\Crm Contacts ApiException:try ?§response = $hubspot->crm->contacts->basicApi->create($input):}catch (ApiException $e) {sstatus=se->cetlodeo:400sbodySheaders = SeSe->getResoonseBodvo:I/ raw JSON string with the erronпяшелецВанениько сауинКО сОмоуСОIо са сOLOTOUAсDOD-1144 US-SY0S0TUZaE44Yn UaCe LUN O8450006-[CREDIT_CARD]" "noacon"."(4Azl Cljent ennoprospect caca luentltleУрес епаль, поепешелс пикосау.лико сомодшалпу,сош а сомешастог дао торесоро-итат-4тоз-аб4-7050т02ае44Yest"} {"correlation id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449" "trace id":"8e45bIcer":10,"pol1cy:null,"reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/0bzecrs/concact/ searchresulced in a 42y 100 Many kequest5/0"Job_cLass": "Jamanny (Jobs \\Crm\ \MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9€emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-ba1ontact_ id":null. "lead_id":null}l} {"coractivities","entityId":614382,"collectionKey":"activities-for-update-pricontact idi.null "lead idi.nulllil Siconrrelation_id":"78f847cf-6495-4054-b3d4-e179a133bd42" "trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}dencitler": "n1kolay.n1ko Lovo 1m1nnyTATEESSTATITTILBACO:FDWNAITUANLTTKTATTTBAYEE ETATATN ATAS ITATAT A : EТ/Т:: ПТЕТУЕИT10b class". "JaminnyJobs urm Macchacciv1cyurmuar.cipants":"1d": 100"opportunity id":22."staqe_id":89}} {'"trace_1d": "8e450868-22b5-42f8-a97":nulur *"conWrite a message…Opus 4.7 Adaptivemethod "identifierlK Lukas. ProCaudo ic Aland can mako mictakac Plesce double-chock recnoncod...
|
17896
|
NULL
|
NULL
|
NULL
|
|
17897
|
780
|
28
|
2026-05-11T10:40:22.542527+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496022542_m1.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER2,5₴81DE SlackFileEditViewGoHistoryWindowHelpDOCKER2,5₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More> 0.ED→Jiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0::: AppsS Jira CloudToastGanala CalaSupport Daily • in 1h 20 m100% <78• Mon 11 May 13:40:22Describe what you are looking forToastHomeMessagesAboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~NewToast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+Aa...
|
NULL
|
-806495445790083024
|
NULL
|
visual_change
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER2,5₴81DE SlackFileEditViewGoHistoryWindowHelpDOCKER2,5₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More> 0.ED→Jiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0::: AppsS Jira CloudToastGanala CalaSupport Daily • in 1h 20 m100% <78• Mon 11 May 13:40:22Describe what you are looking forToastHomeMessagesAboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~NewToast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+Aa...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17896
|
781
|
24
|
2026-05-11T10:40:20.248913+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496020248_m2.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code+ New chatã Projectso0 Arutacts₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectScreenpipe sync script talling arter recelMonthly expense trackingExporting transaction data from Notion t® How much have I spent for groc...April 2026 spending by categoryCode diff reviewnuospot rate limit imolementation strateScreenpipe retention policy code locatio!Viewing retention policy in screenpipeClean shot x video recording terminationHubSpot rate limit handling with executeUntitled@ Screen pine. Is there abilitv…SMB mount access inconsistencv betweWhat is the best switch I can….Permission denied on screenpipe volumeScreenpipe sync database attachment erLast swimming outing with Dan.Chromecast remote volume buttons noti/service.phpest.ongReader ModeSupport Daily - in 1h 20m100% 1Mon 11 May 13:40:20= custom.logE laravel.logxReceived 429 from APIA console [STAGING]Cc W .*X 1155emote_search":true, "set_configuration":2, "old_state" : {"Lead_id":null, "contact_id":null, "account_id":26 , "opportunity_id":22, "stage_id":89}} factivities", "entityld":615092, "collectionKey": "activities-for-update-priority", "withPriority":true} {"correlation_id":"fObecb3b-1f4f-4fb3-a31"contact_id":null, "Lead_id":null}]} {"cor":"hubspot"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"}* Good afternoon, LukasHow can I help you today?пAеICцанениько сауинКО сОмоСОIо са сOU OUU-1144 USSY0SOTUZaE44Yn UaCe LUN O8450006-4005-441070710-24#noacon"."rhazl Client ennorprospect caca luentltleest"r ""correlacion 10: T0becb5d-1t4t-4tb5-a511-Y056t0zae447, "Crace 10": 80454cer":10,"poL1Cy":null, "reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/0bzecrs/concact/searchresulced in a 42y 100 Many Kequest5/0"job_class":"Jiminny| \Jobs||Crm) \MatchActivityCrmData", "attempts":1, "retry_after":10, "delay":14} ("correlation_id": "fObecb3b-1f4f-4fb3-a311-9emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-bar:89, "contact_id":null, "lead_id":nullfl} f"cor& WriteQ Learn" CodeOpus 4.7 Adaptive vLife stuff• Claude's choiceNNNNNcontact_id" :null, "lead_id":nullfl} {"cordenciter": "n1kolay.n1ko Lovd1m1nny10b class". "JaminnyJobs urm Macchaciv1cyurmuar.TATEESSTATITTILBACOFDWNAITUANLTTKTATTTBAYEE ETATATN ATAS ITATAT A :EТ/Т:: ПТЕТУЕИTcipants"opportunity id":22."staqe_id":89}} {'"trace_1d": "8e450868-2eb5-42f8-a91d":nulzr *"conmethod "identifierlK Lukas. Pro...
|
NULL
|
-7932292214112278759
|
NULL
|
visual_change
|
ocr
|
NULL
|
claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code claudecalVIeWWindowmelp0, Chat:= Cowork‹/> Code+ New chatã Projectso0 Arutacts₴ CustomizeBu garian cit zenshio apolication proces:Dawarich location tracking projectScreenpipe sync script talling arter recelMonthly expense trackingExporting transaction data from Notion t® How much have I spent for groc...April 2026 spending by categoryCode diff reviewnuospot rate limit imolementation strateScreenpipe retention policy code locatio!Viewing retention policy in screenpipeClean shot x video recording terminationHubSpot rate limit handling with executeUntitled@ Screen pine. Is there abilitv…SMB mount access inconsistencv betweWhat is the best switch I can….Permission denied on screenpipe volumeScreenpipe sync database attachment erLast swimming outing with Dan.Chromecast remote volume buttons noti/service.phpest.ongReader ModeSupport Daily - in 1h 20m100% 1Mon 11 May 13:40:20= custom.logE laravel.logxReceived 429 from APIA console [STAGING]Cc W .*X 1155emote_search":true, "set_configuration":2, "old_state" : {"Lead_id":null, "contact_id":null, "account_id":26 , "opportunity_id":22, "stage_id":89}} factivities", "entityld":615092, "collectionKey": "activities-for-update-priority", "withPriority":true} {"correlation_id":"fObecb3b-1f4f-4fb3-a31"contact_id":null, "Lead_id":null}]} {"cor":"hubspot"} {"correlation_id":"fObecb3b-1f4f-4fb3-a311-9056fd2ae449", "trace_id": "8e45b868-2eb5-42f8-a91e-22951e49d57d"}* Good afternoon, LukasHow can I help you today?пAеICцанениько сауинКО сОмоСОIо са сOU OUU-1144 USSY0SOTUZaE44Yn UaCe LUN O8450006-4005-441070710-24#noacon"."rhazl Client ennorprospect caca luentltleest"r ""correlacion 10: T0becb5d-1t4t-4tb5-a511-Y056t0zae447, "Crace 10": 80454cer":10,"poL1Cy":null, "reason":"Cllent error:rusinecps:ap1.hubap1.com/crm/vs/0bzecrs/concact/searchresulced in a 42y 100 Many Kequest5/0"job_class":"Jiminny| \Jobs||Crm) \MatchActivityCrmData", "attempts":1, "retry_after":10, "delay":14} ("correlation_id": "fObecb3b-1f4f-4fb3-a311-9emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-01ef-46ae-bar:89, "contact_id":null, "lead_id":nullfl} f"cor& WriteQ Learn" CodeOpus 4.7 Adaptive vLife stuff• Claude's choiceNNNNNcontact_id" :null, "lead_id":nullfl} {"cordenciter": "n1kolay.n1ko Lovd1m1nny10b class". "JaminnyJobs urm Macchaciv1cyurmuar.TATEESSTATITTILBACOFDWNAITUANLTTKTATTTBAYEE ETATATN ATAS ITATAT A :EТ/Т:: ПТЕТУЕИTcipants"opportunity id":22."staqe_id":89}} {'"trace_1d": "8e450868-2eb5-42f8-a91d":nulzr *"conmethod "identifierlK Lukas. Pro...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17895
|
780
|
27
|
2026-05-11T10:40:19.578395+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496019578_m1.jpg...
|
Notion Calendar
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKERLastlogi SlackFileEditViewGoHistoryWindowHelpDOCKERLastlogin:₴81DEV (docker)Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file inlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0Fks a Boro pect, ton fi if sers/lukos or its parents-zshHomeDMsActivity$1>0.laolSupport Daily • in 1h 20 m100% <78• Mon 11 May 13:40:19ED→Describe what you are looking forJiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office31Clauderercnyurmguura®. Galya Dimitrova L&. Petko Kashinski&. Stefka Stoyanovae. Vasil Vasilev O!&. Nikolay Ivanov(3 Aneliya Angelova, ...Stoyan Tanev. VesE Lukas Kovalik y...::: Apps$ Jira CloudToastCanalo CalaToastHomeMessagesAboutFriday, May 8th~iminnyAdded by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+AaNew...
|
NULL
|
5122720637970726791
|
NULL
|
visual_change
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKERLastlogi SlackFileEditViewGoHistoryWindowHelpDOCKERLastlogin:₴81DEV (docker)Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file inlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0Fks a Boro pect, ton fi if sers/lukos or its parents-zshHomeDMsActivity$1>0.laolSupport Daily • in 1h 20 m100% <78• Mon 11 May 13:40:19ED→Describe what you are looking forJiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office31Clauderercnyurmguura®. Galya Dimitrova L&. Petko Kashinski&. Stefka Stoyanovae. Vasil Vasilev O!&. Nikolay Ivanov(3 Aneliya Angelova, ...Stoyan Tanev. VesE Lukas Kovalik y...::: Apps$ Jira CloudToastCanalo CalaToastHomeMessagesAboutFriday, May 8th~iminnyAdded by Toast for GitHubToday ~Toast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+AaNew...
|
17893
|
NULL
|
NULL
|
NULL
|
|
17894
|
781
|
23
|
2026-05-11T10:40:13.741320+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496013741_m2.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Search
BadRequest \SevenShores\Hubspot\Exception Search
BadRequest \SevenShores\Hubspot\Exceptions
BadRequest \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
Choose Implementation of HubspotException \SevenShores\Hubspot\Exceptions (2 found)
Open in Find Tool Window...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Search","depth":1,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"BadRequest \\SevenShores\\Hubspot\\Exceptions","depth":4,"bounds":{"left":0.20246011,"top":0.2857143,"width":0.20777926,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"BadRequest \\SevenShores\\Hubspot\\Exceptions","depth":5,"bounds":{"left":0.27027926,"top":1.0,"width":0.12965426,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubspotException \\SevenShores\\Hubspot\\Exceptions","depth":4,"bounds":{"left":0.20246011,"top":0.30327216,"width":0.20777926,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotException \\SevenShores\\Hubspot\\Exceptions","depth":5,"bounds":{"left":0.27027926,"top":1.0,"width":0.12965426,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Choose Implementation of HubspotException \\SevenShores\\Hubspot\\Exceptions (2 found)","depth":1,"bounds":{"left":0.20578457,"top":0.25937748,"width":0.19182181,"height":0.026336791},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":1,"bounds":{"left":0.39893618,"top":0.26256984,"width":0.0013297872,"height":0.019952115},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Open in Find Tool Window","depth":1,"bounds":{"left":0.40026596,"top":0.26256984,"width":0.005319149,"height":0.019952115},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8828321877940500468
|
-1194196740997002560
|
click
|
accessibility
|
NULL
|
Search
BadRequest \SevenShores\Hubspot\Exception Search
BadRequest \SevenShores\Hubspot\Exceptions
BadRequest \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
Choose Implementation of HubspotException \SevenShores\Hubspot\Exceptions (2 found)
Open in Find Tool Window...
|
17891
|
NULL
|
NULL
|
NULL
|
|
17893
|
780
|
26
|
2026-05-11T10:40:13.731346+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496013731_m1.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Search
BadRequest \SevenShores\Hubspot\Exception Search
BadRequest \SevenShores\Hubspot\Exceptions
BadRequest \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
Choose Implementation of HubspotException \SevenShores\Hubspot\Exceptions (2 found)
Open in Find Tool Window...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Search","depth":1,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"BadRequest \\SevenShores\\Hubspot\\Exceptions","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"BadRequest \\SevenShores\\Hubspot\\Exceptions","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.27083334,"height":0.022222223},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubspotException \\SevenShores\\Hubspot\\Exceptions","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotException \\SevenShores\\Hubspot\\Exceptions","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.27083334,"height":0.022222223},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Choose Implementation of HubspotException \\SevenShores\\Hubspot\\Exceptions (2 found)","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Open in Find Tool Window","depth":1,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8828321877940500468
|
-1194196740997002560
|
click
|
accessibility
|
NULL
|
Search
BadRequest \SevenShores\Hubspot\Exception Search
BadRequest \SevenShores\Hubspot\Exceptions
BadRequest \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
HubspotException \SevenShores\Hubspot\Exceptions
Choose Implementation of HubspotException \SevenShores\Hubspot\Exceptions (2 found)
Open in Find Tool Window...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17892
|
780
|
25
|
2026-05-11T10:40:11.356915+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496011356_m1.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/BadRequest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Received 429 from API","depth":4,"on_screen":true,"value":"Received 429 from API","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8804189326572351292
|
-8127776851674060534
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
SlackFileEditViewGoHistoryWindowHelpDOCKER₴81DEV (docker)Last login: Sun May 10 21:10:26 on ttys013₴2APP (-zsh)883Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ 0-zshHomeDMsActivityFilesLater..•More> 0.EDlaol→Jiminny ...# conrusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...^ Direct messages®. Aneliya Angelova®. Galya Dimitrova& Petko Kashinski&. Stefka StoyanovaVasil Vasilev el&. Nikolay IvanovAneliya Angelova, ...Stoyan Tanev• VesE Lukas Kovalik y... 0::: AppsS Jira CloudToastGanala CalaSupport Daily - in 1h 20 m100% <78• Mon 11 May 13:40:10Describe what you are looking forToastHomeMessagesAboutiminnyFriday, May 8th ~Added by Toast for GitHubToday ~NewToast APP10:00 AMReviewapp#12059 Jy 20820 es reindexstream model hydration2 days old • 12 files changed •@Vasil VasilevAdded by Toast for GitHubResolve Conflictsapp#11443 Test hublets latency5 months old • 20 files changed#11327 JY-19501 webhookbased opportunity syncShow moreAdded by Toast for GitHubNeeds Loveapp#12024 JY-20773 fix user pilottracking ofr automated reportgenerated12 days old • 1 file changedMessage Toast+Aa...
|
17889
|
NULL
|
NULL
|
NULL
|
|
17891
|
781
|
22
|
2026-05-11T10:40:11.168583+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496011168_m2.jpg...
|
PhpStorm
|
faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-p faVsco.js – ~/jiminny/app/vendor/hubspot/hubspot-php/src/Exceptions/BadRequest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/5
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
342
Previous Highlighted Error
Next Highlighted Error
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":615092,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":615092} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":615092,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {"activity":615092,"participants":[{"id":1004102,"user_id":null,"contact_id":null,"lead_id":null},{"id":1004103,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {"email":"[EMAIL]","reason":"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {"exception_class":"SevenShores\\Hubspot\\Exceptions\\BadRequest"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"policy":null,"reason":"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:
{\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019e168a-5 (truncated...)
"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614436,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614436} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614436,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614436,"participants":[{"id":1002751,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002752,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614382,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614382} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614382,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614382,"participants":[{"id":1002632,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002633,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614381,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614381} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614381,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614381,"participants":[{"id":1002630,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002631,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614378,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":6167,"account_id":null,"opportunity_id":null,"stage_id":null}} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614378} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614378,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614378,"participants":[{"id":1002623,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002624,"user_id":null,"contact_id":6167,"lead_id":null},{"id":1002625,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":15} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613840,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613840} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613840,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613840,"participants":[{"id":1001764,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001765,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: ProspectCache - Searching DB for opportunity by owner {"account_id":244,"contact_id":4487,"owner_id":261} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: ProspectCache - Opportunity DB search results {"account_id":244,"contact_id":4487,"opportunity_id":299} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613840,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613840,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613840} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613840,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613840,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613833,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613833} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613833,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613833,"participants":[{"id":1001750,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001751,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613833,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613833,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613833} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613833,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613833,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613827,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613827} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613827,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613827,"participants":[{"id":1001734,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001735,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613827,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613827,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613827} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613827,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613827,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613826,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613826} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613826,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613826,"participants":[{"id":1001732,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001733,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613826,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613826,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613826} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613826,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613826,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613820,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613820} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613820,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613820,"participants":[{"id":1001721,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001722,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613820,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613820,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613820} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613820,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613820,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613818,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613818} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613818,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613818,"participants":[{"id":1001717,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001718,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613818,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613818,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613818} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613818,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613818,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613812,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613812} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613812,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613812,"participants":[{"id":1001705,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001706,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613812,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613812,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613812} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613812,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613812,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613807,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4484,"account_id":243,"opportunity_id":276,"stage_id":36}} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613807} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613807,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613807,"participants":[{"id":1001690,"user_id":253,"contact_id":null,"lead_id":null},{"id":1001691,"user_id":null,"contact_id":4484,"lead_id":null}]} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613807,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {"account_id":243,"contact_id":4484,"owner_id":253} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {"account_id":243,"contact_id":4484} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {"account_id":243,"contact_id":4484,"opportunity_id":276} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613807,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613807} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613807,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613807,"remote_search"...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reader Mode","depth":4,"bounds":{"left":0.5415558,"top":0.17318435,"width":0.034574468,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","depth":4,"bounds":{"left":0.11968085,"top":0.17158818,"width":0.47805852,"height":0.8076616},"on_screen":true,"lines":[{"char_start":7,"char_count":42,"bounds":{"left":0.11968085,"top":0.0,"width":0.10605053,"height":0.014365523}},{"char_start":50,"char_count":42,"bounds":{"left":0.11968085,"top":0.0,"width":0.10605053,"height":0.014365523}},{"char_start":92,"char_count":2,"bounds":{"left":0.11968085,"top":0.0,"width":0.0026595744,"height":0.014365523}},{"char_start":94,"char_count":1,"bounds":{"left":0.11968085,"top":0.0,"width":0.0026595744,"height":0.014365523}}],"value":"<?php\n\nnamespace SevenShores\\Hubspot\\Exceptions;\n\nclass BadRequest extends HubspotException\n{\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"bounds":{"left":0.60206115,"top":0.08060654,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"bounds":{"left":0.6146942,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Received 429 from API","depth":4,"bounds":{"left":0.6256649,"top":0.07980846,"width":0.0631649,"height":0.015961692},"on_screen":true,"value":"Received 429 from API","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.6978058,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"bounds":{"left":0.7077792,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"bounds":{"left":0.71642286,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"bounds":{"left":0.7250665,"top":0.07980846,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1/5","depth":4,"bounds":{"left":0.7386968,"top":0.079010375,"width":0.025598405,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"bounds":{"left":0.7642952,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"bounds":{"left":0.77293885,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"bounds":{"left":0.7815825,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Window, Multiple Cursors","depth":4,"bounds":{"left":0.79022604,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Click to highlight","depth":4,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":4,"bounds":{"left":0.97539896,"top":0.07821229,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"342","depth":4,"bounds":{"left":0.95977396,"top":0.10933759,"width":0.012632979,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.10774142,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.10774142,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-5 (truncated...)\n\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613840,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613840,\"participants\":[{\"id\":1001764,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001765,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613840,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613840,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613840,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613833,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613833,\"participants\":[{\"id\":1001750,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001751,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613833,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613833,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613833,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613827,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613827,\"participants\":[{\"id\":1001734,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001735,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613827,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613827,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613827,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613826,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613826,\"participants\":[{\"id\":1001732,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001733,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613826,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613826,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613826,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613820,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613820,\"participants\":[{\"id\":1001721,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001722,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613820,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613820,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613820,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613818,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613818,\"participants\":[{\"id\":1001717,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001718,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613818,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613818,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613818,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613812,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613812,\"participants\":[{\"id\":1001705,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001706,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613812,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613812,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613812,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613807,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613807,\"participants\":[{\"id\":1001690,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001691,\"user_id\":null,\"contact_id\":4484,\"lead_id\":null}]} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613807,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4484,\"owner_id\":253} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4484} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4484,\"opportunity_id\":276} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"tsvetomir.banovski@gmail.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613807,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613807,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613806,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613806,\"participants\":[{\"id\":1001688,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001689,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613806,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":253} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613806,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613806,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613805,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613805,\"participants\":[{\"id\":1001686,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001687,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613805,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613805,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613805,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613698,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613698,\"participants\":[{\"id\":1001667,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001668,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613698,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613698,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613698,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613697,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613697,\"participants\":[{\"id\":1001665,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001666,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613697,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613697,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613697,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613696,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613696,\"participants\":[{\"id\":1001663,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001664,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613696,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613696,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613696,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613695,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613695,\"participants\":[{\"id\":1001661,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001662,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613695,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613695,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613695,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613694,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613694,\"participants\":[{\"id\":1001659,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001660,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613694,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613694,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613694,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613157,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613157,\"participants\":[{\"id\":1000746,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000747,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613157,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613157,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613157,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613156,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613156,\"participants\":[{\"id\":1000744,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000745,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613156,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613156,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613156,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613155,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613155,\"participants\":[{\"id\":1000742,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000743,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613155,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613155,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613155,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613130,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613130,\"participants\":[{\"id\":1000693,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000694,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613130,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613130,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613130,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612924,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612924,\"participants\":[{\"id\":1000290,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000291,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612924,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":19} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":165} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612924,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612924,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612923,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612923,\"participants\":[{\"id\":1000288,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000289,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612923,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612923,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612923,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612922,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612922,\"participants\":[{\"id\":1000286,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000287,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612922,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612922,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612922,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612822,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612822,\"participants\":[{\"id\":1000080,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000081,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612822,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612822,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612822,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612673,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612673,\"participants\":[{\"id\":999993,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999994,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612673,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612673,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612673,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612642,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612642,\"participants\":[{\"id\":999935,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999936,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612642,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612642,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612642,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612598,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612598,\"participants\":[{\"id\":999857,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999858,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612598,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612598,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612598,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612597,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612597,\"participants\":[{\"id\":999855,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999856,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612597,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612597,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612597,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612596,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612596,\"participants\":[{\"id\":999853,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999854,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612596,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612596,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612596,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612595,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612595,\"participants\":[{\"id\":999851,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999852,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612595,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612595,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612595,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612594,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612594,\"participants\":[{\"id\":999849,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999850,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612594,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612594,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612594,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612593,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612593,\"participants\":[{\"id\":999847,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999848,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612593,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612593,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612593,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612592,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612592,\"participants\":[{\"id\":999845,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999846,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612592,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612592,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612592,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612591,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612591,\"participants\":[{\"id\":999843,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999844,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612591,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612591,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612591,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612590,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612590,\"participants\":[{\"id\":999841,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999842,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612590,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612590,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612590,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612589,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612589,\"participants\":[{\"id\":999839,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999840,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612589,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612589,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612589,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612588,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612588,\"participants\":[{\"id\":999837,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999838,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612588,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612588,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612588,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612587,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612587,\"participants\":[{\"id\":999835,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999836,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612587,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612587,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612587,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612586,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612586,\"participants\":[{\"id\":999833,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999834,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612586,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612586,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612586,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612585,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612585,\"participants\":[{\"id\":999831,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999832,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612585,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612585,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612585,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612584,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612584,\"participants\":[{\"id\":999829,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999830,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612584,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612584,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612584,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612583,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612583,\"participants\":[{\"id\":999827,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999828,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612583,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612583,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612583,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612582,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612582,\"participants\":[{\"id\":999825,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999826,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612582,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612582,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612582,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612581,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612581,\"participants\":[{\"id\":999823,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999824,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612581,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612581,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612581,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612565,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612565,\"participants\":[{\"id\":999789,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999790,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612565,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612565,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612565,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612563,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612563,\"participants\":[{\"id\":999784,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999785,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612563,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":206} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612563,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612563,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612559,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612559,\"participants\":[{\"id\":999776,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999777,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612559,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":206} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":69,\"contact_id\":97} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":5011} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612559,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612559,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612558,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612558,\"participants\":[{\"id\":999774,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999775,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612558,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612558,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612558,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612557,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612557,\"participants\":[{\"id\":999772,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999773,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612557,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612557,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612557,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612556,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612556,\"participants\":[{\"id\":999770,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999771,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612556,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612556,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612556,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612555,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612555,\"participants\":[{\"id\":999768,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999769,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612555,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612555,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612555,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":11.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612554,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612554,\"participants\":[{\"id\":999766,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999767,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612554,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612554,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612554,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612553,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612553,\"participants\":[{\"id\":999764,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999765,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612553,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612553,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612553,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612552,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612552,\"participants\":[{\"id\":999762,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999763,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612552,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612552,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612552,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612551,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612551,\"participants\":[{\"id\":999760,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999761,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612551,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612551,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612551,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612550,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612550,\"participants\":[{\"id\":999758,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999759,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612550,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612550,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612550,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612549,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612549,\"participants\":[{\"id\":999756,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999757,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612549,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612549,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612549,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612365,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612365,\"participants\":[{\"id\":999563,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999564,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612365,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612365,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612365,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-9 (truncated...)\n\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612183,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612183,\"participants\":[{\"id\":999227,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999228,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612183,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612183,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612183,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612182,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612182,\"participants\":[{\"id\":999225,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999226,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612182,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612182,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612182,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.26,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612181,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612181,\"participants\":[{\"id\":999223,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999224,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612181,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612181,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612181,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612180,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612180,\"participants\":[{\"id\":999221,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999222,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612180,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612180,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612180,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.9,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-c (truncated...)\n\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610400,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610400,\"participants\":[{\"id\":996275,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null},{\"id\":996276,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":996277,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":1460} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610400,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610400,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring start {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring end {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"f6431de6-0cbf-4083-96fc-d316ebac17ec\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-e (truncated...)\n\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.21,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.19,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168b-1 (truncated...)\n\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.31,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.47,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:04] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.3,\"average_seconds_per_request\":0.3} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610539,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610539,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610539,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610878,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610878,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610878,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.25,\"average_seconds_per_request\":0.25} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.48,\"average_seconds_per_request\":0.48} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612340,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612340,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612360,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612360,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612339,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612339,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.66,\"average_seconds_per_request\":0.66} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.3,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.26,\"average_seconds_per_request\":0.26} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611455,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611455,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611455,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610915,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610915,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610915,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610528,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610528,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610528,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611087,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611087,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611087,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611076,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611076,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611076,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610497,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610497,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610497,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610867,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610867,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610867,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610490,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610490,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610490,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610506,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610506,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610506,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610885,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610885,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610885,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610874,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610874,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610874,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610617,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610617,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610617,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring start {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring end {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.42,\"average_seconds_per_request\":0.42} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614382,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614382,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614382,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614381,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614381,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614381,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.55,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610426,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610426,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610426,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612560,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612560,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612560,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610462,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610462,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610462,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612819,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612819,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612847,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612847,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612847,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612562,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612562,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612562,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610764,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610764,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610764,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614436,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614436,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614436,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610438,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610438,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610438,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":615092,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":615092,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":615092,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610403,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610403,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610403,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610935,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610935,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610935,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610470,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610470,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610470,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610900,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610900,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610900,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nmalchev@gmail.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614378,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614378,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614378,\"remote_search\":true,\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612561,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612561,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612336,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612336,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.38,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring start {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring end {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:20:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2fa5b0c6-7488-44c6-93cb-2c97d3dd0e22\",\"trace_id\":\"ba4e66e9-8f87-4745-8d42-1a604ad0e217\"}\n[2026-05-11 10:20:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"2fa5b0c6-7488-44c6-93cb-2c97d3dd0e22\",\"trace_id\":\"ba4e66e9-8f87-4745-8d42-1a604ad0e217\"}\n[2026-05-11 10:20:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2fa5b0c6-7488-44c6-93cb-2c97d3dd0e22\",\"trace_id\":\"ba4e66e9-8f87-4745-8d42-1a604ad0e217\"}\n[2026-05-11 10:20:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ff04c3c8-37ec-4fc2-a6b3-b821bfa798a1\",\"trace_id\":\"8a9e705c-56b1-4d8a-8768-a73d75428bdf\"}\n[2026-05-11 10:20:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ff04c3c8-37ec-4fc2-a6b3-b821bfa798a1\",\"trace_id\":\"8a9e705c-56b1-4d8a-8768-a73d75428bdf\"}\n[2026-05-11 10:20:12] local.NOTICE: Monitoring start {\"correlation_id\":\"add6d280-ba4b-4bed-b685-48f6c7138f63\",\"trace_id\":\"b73d73a4-10a3-405e-b1d8-c28149fd02e7\"}\n[2026-05-11 10:20:12] local.NOTICE: Monitoring end {\"correlation_id\":\"add6d280-ba4b-4bed-b685-48f6c7138f63\",\"trace_id\":\"b73d73a4-10a3-405e-b1d8-c28149fd02e7\"}\n[2026-05-11 10:20:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b6f27226-9ba6-476a-97c7-2f979b24192e\",\"trace_id\":\"d8265844-c686-42da-aec4-a3935c6e7846\"}\n[2026-05-11 10:20:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b6f27226-9ba6-476a-97c7-2f979b24192e\",\"trace_id\":\"d8265844-c686-42da-aec4-a3935c6e7846\"}\n[2026-05-11 10:20:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:16] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:16] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:17] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:18:00, 2026-05-11 10:20:00] {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:17] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:18:00, 2026-05-11 10:20:00] {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"96a418e4-766c-47b9-a1ff-954e236284b0\",\"trace_id\":\"183cebf6-abdc-43c0-9553-d92b54ed6aee\"}\n[2026-05-11 10:20:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"96a418e4-766c-47b9-a1ff-954e236284b0\",\"trace_id\":\"183cebf6-abdc-43c0-9553-d92b54ed6aee\"}\n[2026-05-11 10:20:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"72dc0355-eaa2-49c7-8505-d6878c6979cf\",\"trace_id\":\"7116edfd-f3c9-421f-8da0-c974bcc89b30\"}\n[2026-05-11 10:20:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"72dc0355-eaa2-49c7-8505-d6878c6979cf\",\"trace_id\":\"7116edfd-f3c9-421f-8da0-c974bcc89b30\"}\n[2026-05-11 10:20:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"13f58aec-c028-4abd-a682-187350d1dfeb\",\"trace_id\":\"c33a24c2-2793-4a9e-86a3-baf7fa638e43\"}\n[2026-05-11 10:20:21] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"13f58aec-c028-4abd-a682-187350d1dfeb\",\"trace_id\":\"c33a24c2-2793-4a9e-86a3-baf7fa638e43\"}\n[2026-05-11 10:20:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"13f58aec-c028-4abd-a682-187350d1dfeb\",\"trace_id\":\"c33a24c2-2793-4a9e-86a3-baf7fa638e43\"}\n[2026-05-11 10:20:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:22] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:10:00, 2026-05-11 10:15:00] {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:22] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:10:00, 2026-05-11 10:15:00] {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:23] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:15\",\"to\":\"10:20\"} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:23] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:10\",\"to\":\"00:15\"} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:25] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:25] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:25] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0abde2a5-83dc-444e-9372-f2134403833e\",\"trace_id\":\"265d74d8-d739-4506-98fa-d7528a97a6a9\"}\n[2026-05-11 10:20:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"58b4e029-5c87-4bfd-97d9-bf09f07de93d\",\"trace_id\":\"019a9c46-da79-4fb0-bbfc-a1adc73d1bc1\"}\n[2026-05-11 10:20:28] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:28] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:28] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:22:28.938115Z\"} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"58b4e029-5c87-4bfd-97d9-bf09f07de93d\",\"trace_id\":\"019a9c46-da79-4fb0-bbfc-a1adc73d1bc1\"}\n[2026-05-11 10:20:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0abde2a5-83dc-444e-9372-f2134403833e\",\"trace_id\":\"265d74d8-d739-4506-98fa-d7528a97a6a9\"}\n[2026-05-11 10:20:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"55b75dbc-a484-4333-98cd-73ddfc7ac530\",\"trace_id\":\"a35f4804-0635-4e5f-bc3e-2ca67f4a6de4\"}\n[2026-05-11 10:20:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"55b75dbc-a484-4333-98cd-73ddfc7ac530\",\"trace_id\":\"a35f4804-0635-4e5f-bc3e-2ca67f4a6de4\"}\n[2026-05-11 10:20:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"adf166f0-57f0-46a9-a389-9ff0cf327f8c\",\"trace_id\":\"022378eb-a08a-458a-a6e0-91facbd00432\"}\n[2026-05-11 10:20:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"adf166f0-57f0-46a9-a389-9ff0cf327f8c\",\"trace_id\":\"022378eb-a08a-458a-a6e0-91facbd00432\"}\n[2026-05-11 10:20:34] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:39] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:54] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cb3067bf-9fb7-4f4a-9bed-cd02cf91a685\",\"trace_id\":\"48a1ca4a-e7f4-4e27-9300-e9d31e949410\"}\n[2026-05-11 10:21:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"cb3067bf-9fb7-4f4a-9bed-cd02cf91a685\",\"trace_id\":\"48a1ca4a-e7f4-4e27-9300-e9d31e949410\"}\n[2026-05-11 10:21:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cb3067bf-9fb7-4f4a-9bed-cd02cf91a685\",\"trace_id\":\"48a1ca4a-e7f4-4e27-9300-e9d31e949410\"}\n[2026-05-11 10:21:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4d0f11d7-a469-47a8-8117-621c74048dfb\",\"trace_id\":\"5de7b33f-4f7f-4110-9e8f-6b436d79ade0\"}\n[2026-05-11 10:21:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4d0f11d7-a469-47a8-8117-621c74048dfb\",\"trace_id\":\"5de7b33f-4f7f-4110-9e8f-6b436d79ade0\"}\n[2026-05-11 10:21:08] local.NOTICE: Monitoring start {\"correlation_id\":\"6bdd22fb-795a-45fd-8b9f-7a828d72d3ff\",\"trace_id\":\"ee68ac31-0507-4f4c-851f-fed983af5b11\"}\n[2026-05-11 10:21:08] local.NOTICE: Monitoring end {\"correlation_id\":\"6bdd22fb-795a-45fd-8b9f-7a828d72d3ff\",\"trace_id\":\"ee68ac31-0507-4f4c-851f-fed983af5b11\"}\n[2026-05-11 10:21:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"23d6dfa8-a7c5-4e07-9560-ac2b9edca59b\",\"trace_id\":\"8daa12ab-4140-48cc-865f-8caf73c4756d\"}\n[2026-05-11 10:21:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"23d6dfa8-a7c5-4e07-9560-ac2b9edca59b\",\"trace_id\":\"8daa12ab-4140-48cc-865f-8caf73c4756d\"}\n[2026-05-11 10:21:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:11] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:11] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"dca67603-c9be-467a-bfe4-2b74567cac53\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"dca67603-c9be-467a-bfe4-2b74567cac53\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24178328,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.31,\"average_seconds_per_request\":0.31} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":339.28} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":425.88,\"usage\":24265920,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24243920,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.69,\"usage\":24254648,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24212152,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":6.73,\"usage\":24228272,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24188912,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":10.24,\"usage\":24231856,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":57,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":177.4,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:22:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3bf2248c-ad1e-435e-87aa-ac94afaddee2\",\"trace_id\":\"3c60287a-2ec2-4ae8-8ce7-0f2589186a27\"}\n[2026-05-11 10:22:08] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"3bf2248c-ad1e-435e-87aa-ac94afaddee2\",\"trace_id\":\"3c60287a-2ec2-4ae8-8ce7-0f2589186a27\"}\n[2026-05-11 10:22:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3bf2248c-ad1e-435e-87aa-ac94afaddee2\",\"trace_id\":\"3c60287a-2ec2-4ae8-8ce7-0f2589186a27\"}\n[2026-05-11 10:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cc7263ec-0925-4031-8df0-79534a303c7b\",\"trace_id\":\"b72980a3-0c17-453c-829a-8757cac12f35\"}\n[2026-05-11 10:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cc7263ec-0925-4031-8df0-79534a303c7b\",\"trace_id\":\"b72980a3-0c17-453c-829a-8757cac12f35\"}\n[2026-05-11 10:22:14] local.NOTICE: Monitoring start {\"correlation_id\":\"480dd732-d728-4670-9484-e9c2def7b3c1\",\"trace_id\":\"daef0ed3-e82d-4316-b8ab-b03ea2a814e1\"}\n[2026-05-11 10:22:14] local.NOTICE: Monitoring end {\"correlation_id\":\"480dd732-d728-4670-9484-e9c2def7b3c1\",\"trace_id\":\"daef0ed3-e82d-4316-b8ab-b03ea2a814e1\"}\n[2026-05-11 10:22:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"045e36da-9d9e-48c0-86f5-57240fcc0474\",\"trace_id\":\"50851e0f-b51f-46b7-8267-3b34dc31d290\"}\n[2026-05-11 10:22:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"045e36da-9d9e-48c0-86f5-57240fcc0474\",\"trace_id\":\"50851e0f-b51f-46b7-8267-3b34dc31d290\"}\n[2026-05-11 10:22:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:30] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:20:00, 2026-05-11 10:22:00] {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:30] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:20:00, 2026-05-11 10:22:00] {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e44d2d83-432a-40dc-82ed-bb636a1162bd\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e5a63cea-0e84-401b-92de-9b1c22e7560e\",\"trace_id\":\"be5864a6-ba9f-45e9-bf23-1059d0c7a8ba\"}\n[2026-05-11 10:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e5a63cea-0e84-401b-92de-9b1c22e7560e\",\"trace_id\":\"be5864a6-ba9f-45e9-bf23-1059d0c7a8ba\"}\n[2026-05-11 10:22:45] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2ab4f96e-cb0c-45c5-aaff-5f11c58c9643\",\"trace_id\":\"7927db97-1937-43e9-bc89-cae94ed54be7\"}\n[2026-05-11 10:22:45] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2ab4f96e-cb0c-45c5-aaff-5f11c58c9643\",\"trace_id\":\"7927db97-1937-43e9-bc89-cae94ed54be7\"}\n[2026-05-11 10:22:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"connect-and-sell\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Start user synchronisation {\"provider\":\"justcall\",\"teams_count\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Synchronising team {\"provider\":\"justcall\",\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf9285a-8ded-4a8b-bd7d-ec68c398f2f9\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1367,\"sociable_id\":1071,\"provider_user_id\":\"005O4000003s5c7IAA\",\"expires\":null,\"refresh_token_expires\":null,\"provider\":\"salesforce\",\"state\":\"full-refresh\",\"auth_scope\":\"refresh_token web api\",\"retry_after\":null,\"created_at\":\"2024-09-10 07:05:21\",\"updated_at\":\"2026-01-14 07:00:58\"}}} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":1071,\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.WARNING: Failed to sync external users {\"message\":\"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.\",\"provider\":\"justcall\",\"team_id\":1,\"team\":\"jiminny\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"ringcentral\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"avaya\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"telus\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"salesloft\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"talkdesk\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"vonage\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Done {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:23:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"89f4e106-bab3-436f-87ec-18fadaea9834\",\"trace_id\":\"1c6f9a74-e518-4c2f-bbe7-8f453ce1e5db\"}\n[2026-05-11 10:23:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"89f4e106-bab3-436f-87ec-18fadaea9834\",\"trace_id\":\"1c6f9a74-e518-4c2f-bbe7-8f453ce1e5db\"}\n[2026-05-11 10:23:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"89f4e106-bab3-436f-87ec-18fadaea9834\",\"trace_id\":\"1c6f9a74-e518-4c2f-bbe7-8f453ce1e5db\"}\n[2026-05-11 10:23:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"73542ef5-1dcf-49ff-a68f-f3b59f00f8f9\",\"trace_id\":\"53f0e66b-d6a2-4dce-91bc-167397bbcbb4\"}\n[2026-05-11 10:23:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"73542ef5-1dcf-49ff-a68f-f3b59f00f8f9\",\"trace_id\":\"53f0e66b-d6a2-4dce-91bc-167397bbcbb4\"}\n[2026-05-11 10:23:15] local.NOTICE: Monitoring start {\"correlation_id\":\"c42a9140-f8c8-4890-b080-9577f34b4d0b\",\"trace_id\":\"2e2d238c-88b3-467c-80cc-498f7d93d865\"}\n[2026-05-11 10:23:15] local.NOTICE: Monitoring end {\"correlation_id\":\"c42a9140-f8c8-4890-b080-9577f34b4d0b\",\"trace_id\":\"2e2d238c-88b3-467c-80cc-498f7d93d865\"}\n[2026-05-11 10:23:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3fb01e13-10f5-4cdd-b0d2-409650ba47a4\",\"trace_id\":\"e6f9ba96-932b-4bc2-bbb8-2a311b843d97\"}\n[2026-05-11 10:23:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3fb01e13-10f5-4cdd-b0d2-409650ba47a4\",\"trace_id\":\"e6f9ba96-932b-4bc2-bbb8-2a311b843d97\"}\n[2026-05-11 10:23:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:18] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:18] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0334ac42-ef25-4ca6-b9d5-a54eb7340b49\",\"trace_id\":\"4e2661ff-8780-4e2a-9ce3-cb7089e29770\"}\n[2026-05-11 10:23:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0334ac42-ef25-4ca6-b9d5-a54eb7340b49\",\"trace_id\":\"4e2661ff-8780-4e2a-9ce3-cb7089e29770\"}\n[2026-05-11 10:23:31] local.INFO: [integration-app] Request {\"request\":\"GET connections\",\"full_target\":\"connections\"} {\"correlation_id\":\"06a5a57b-ba5f-4fd2-9581-1f1b88dd5218\",\"trace_id\":\"6d3d2375-2629-4141-99e1-2a2421935ebb\"}\n[2026-05-11 10:23:32] local.INFO: [integration-app] Connection state identified {\"teamId\":3143,\"connection_name\":\"Connection to 66fe6c913202f3a165e3c14d for Dev Zoho CRM client\",\"remote_connection_id\":\"69e0b983da98fa74f98aebfb\",\"is_disconnected\":false,\"is_deactivated\":false,\"is_valid\":true} {\"correlation_id\":\"06a5a57b-ba5f-4fd2-9581-1f1b88dd5218\",\"trace_id\":\"6d3d2375-2629-4141-99e1-2a2421935ebb\"}\n[2026-05-11 10:24:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8e890248-7081-459b-86e7-b0eed9ae954a\",\"trace_id\":\"c55f1643-7a81-4ac8-bb91-3a07e96c1371\"}\n[2026-05-11 10:24:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"8e890248-7081-459b-86e7-b0eed9ae954a\",\"trace_id\":\"c55f1643-7a81-4ac8-bb91-3a07e96c1371\"}\n[2026-05-11 10:24:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8e890248-7081-459b-86e7-b0eed9ae954a\",\"trace_id\":\"c55f1643-7a81-4ac8-bb91-3a07e96c1371\"}\n[2026-05-11 10:24:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5c387516-009d-44c8-903a-0e41edb55144\",\"trace_id\":\"909fe43e-4a48-4ce6-9e9f-612e49c4899c\"}\n[2026-05-11 10:24:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5c387516-009d-44c8-903a-0e41edb55144\",\"trace_id\":\"909fe43e-4a48-4ce6-9e9f-612e49c4899c\"}\n[2026-05-11 10:24:12] local.NOTICE: Monitoring start {\"correlation_id\":\"4f81d4a7-cf98-4927-8f5a-073ae73abdb7\",\"trace_id\":\"a697b539-71ff-4407-8b0d-c4430ae15074\"}\n[2026-05-11 10:24:12] local.NOTICE: Monitoring end {\"correlation_id\":\"4f81d4a7-cf98-4927-8f5a-073ae73abdb7\",\"trace_id\":\"a697b539-71ff-4407-8b0d-c4430ae15074\"}\n[2026-05-11 10:24:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e72fbc16-6e70-4c14-8820-a47ad5706362\",\"trace_id\":\"1b6d2b66-bfaa-4d8e-a3ee-9091aa32e8a8\"}\n[2026-05-11 10:24:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e72fbc16-6e70-4c14-8820-a47ad5706362\",\"trace_id\":\"1b6d2b66-bfaa-4d8e-a3ee-9091aa32e8a8\"}\n[2026-05-11 10:24:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:16] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:16] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:17] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:22:00, 2026-05-11 10:24:00] {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:17] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:22:00, 2026-05-11 10:24:00] {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:20] local.ERROR: [Aircall] Re-activating webhooks failed {\"team_id\":1,\"reason\":\"{\\\"message\\\":\\\"Forbidden\\\"}\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:27] local.INFO: [RetryFailedDownloads] Starting {\"options\":{\"from\":null,\"to\":null,\"help\":false,\"silent\":false,\"quiet\":false,\"verbose\":false,\"version\":false,\"ansi\":null,\"no-interaction\":false,\"env\":null}} {\"correlation_id\":\"be1dd357-8994-4b0b-a8e9-f0e7dafe0552\",\"trace_id\":\"b203fd86-cf8b-48c1-a8fb-27ccfe131915\"}\n[2026-05-11 10:25:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3a3ff15c-a907-4597-81c7-53ec1e031983\",\"trace_id\":\"b2f88f98-695d-4635-bfc6-073441408e19\"}\n[2026-05-11 10:25:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"3a3ff15c-a907-4597-81c7-53ec1e031983\",\"trace_id\":\"b2f88f98-695d-4635-bfc6-073441408e19\"}\n[2026-05-11 10:25:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3a3ff15c-a907-4597-81c7-53ec1e031983\",\"trace_id\":\"b2f88f98-695d-4635-bfc6-073441408e19\"}\n[2026-05-11 10:25:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"87f7d7be-b29a-44cc-95db-bc343d1ddc4d\",\"trace_id\":\"6ecc6296-beac-4c8c-8006-2056fb88a912\"}\n[2026-05-11 10:25:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"87f7d7be-b29a-44cc-95db-bc343d1ddc4d\",\"trace_id\":\"6ecc6296-beac-4c8c-8006-2056fb88a912\"}\n[2026-05-11 10:25:13] local.NOTICE: Monitoring start {\"correlation_id\":\"f1f6f9a7-5ae2-4ad0-a221-5259028c26d8\",\"trace_id\":\"fe9ac124-0bcc-4c33-b3d8-bf136686198d\"}\n[2026-05-11 10:25:13] local.NOTICE: Monitoring end {\"correlation_id\":\"f1f6f9a7-5ae2-4ad0-a221-5259028c26d8\",\"trace_id\":\"fe9ac124-0bcc-4c33-b3d8-bf136686198d\"}\n[2026-05-11 10:25:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"13c7c749-aa45-400e-b448-cce1a5ad060d\",\"trace_id\":\"c6715ee4-640f-4933-a8b7-2e896f4a0592\"}\n[2026-05-11 10:25:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"13c7c749-aa45-400e-b448-cce1a5ad060d\",\"trace_id\":\"c6715ee4-640f-4933-a8b7-2e896f4a0592\"}\n[2026-05-11 10:25:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6f625f7c-a2d8-4dab-9230-14a29e565aaa\",\"trace_id\":\"21afd870-871f-48f2-986b-94a4361a3aac\"}\n[2026-05-11 10:25:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6f625f7c-a2d8-4dab-9230-14a29e565aaa\",\"trace_id\":\"21afd870-871f-48f2-986b-94a4361a3aac\"}\n[2026-05-11 10:25:26] local.INFO: [HubSpot Webhook] Signature validation started {\"method\":\"POST\",\"uri\":\"/webhook/conference/hubspot/events\",\"has_v3_signature\":true,\"has_v1_signature\":true} {\"correlation_id\":\"ba3bd7f5-0487-4407-9c46-a117face1f00\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:26] local.INFO: [HubSpot Webhook] Event received {\"payload\":[{\"eventId\":3996584484,\"subscriptionId\":5683263,\"portalId\":4392066,\"appId\":38482,\"occurredAt\":1778472098068,\"subscriptionType\":\"company.propertyChange\",\"attemptNumber\":8,\"objectId\":52628776324,\"propertyName\":\"hubspot_owner_id\",\"propertyValue\":\"\",\"changeSource\":\"CRM_UI\",\"sourceId\":\"userId:45562061\"}],\"event_count\":1} {\"correlation_id\":\"ba3bd7f5-0487-4407-9c46-a117face1f00\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:26] local.INFO: [HubSpot Webhook Job] Processing webhook events {\"event_count\":1,\"local_count\":1,\"forward_count\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:26] local.INFO: [Webhook Forwarder] Forwarding to instance {\"url\":\"https://uranus.staging.jiminny.com/internal/webhook-receiver/hubspot\",\"route\":\"internal.webhook-receiver.hubspot\",\"event_count\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:27] local.ERROR: [Webhook Forwarder] Failed to forward to instance {\"url\":\"https://uranus.staging.jiminny.com\",\"route\":\"internal.webhook-receiver.hubspot\",\"error\":\"Server error: `POST https://uranus.staging.jiminny.com/internal/webhook-receiver/hubspot` resulted in a `503 Service Temporarily Unavailable` response:\n<html>\n\n<head><title>503 Service Temporarily Unavailable</title></head>\n\n<body>\n\n<center><h1>503 Service Temporarily Una (truncated...)\n\",\"code\":503} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:27] local.INFO: [Webhook Forwarder] Forwarding to instance {\"url\":\"https://app.qai.jiminny.com/internal/webhook-receiver/hubspot\",\"route\":\"internal.webhook-receiver.hubspot\",\"event_count\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: [Webhook Forwarder] Successfully forwarded to instance {\"url\":\"https://app.qai.jiminny.com/internal/webhook-receiver/hubspot\",\"status_code\":202,\"response\":{\"status\":\"accepted\",\"message\":\"Events queued for processing\",\"event_count\":1}} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: [HubSpot Webhook] Processing property change event {\"event_type\":\"company.propertyChange\",\"object_id\":52628776324,\"portal_id\":4392066,\"property_name\":\"hubspot_owner_id\",\"property_value\":\"\",\"team_id\":2} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: [BatchSyncCollector] Stored webhook in Redis {\"object_type\":\"company\",\"crm_provider_id\":\"52628776324\",\"event_type\":\"property_change\",\"configuration_id\":2,\"batch_key\":\"batch_sync_company:ids:2:all\",\"was_new\":true,\"current_size\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b2945a08-0aa8-4188-a54e-ebbd99af3536\",\"trace_id\":\"cda58daa-be85-4685-bcaf-fee37ff980b0\"}\n[2026-05-11 10:25:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b2945a08-0aa8-4188-a54e-ebbd99af3536\",\"trace_id\":\"cda58daa-be85-4685-bcaf-fee37ff980b0\"}\n[2026-05-11 10:25:31] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"adb456f4-ddb9-41f8-b32e-99fe065d7b96\",\"trace_id\":\"72c5e7e0-897d-4fe8-9870-46360bfaad50\"}\n[2026-05-11 10:25:31] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"adb456f4-ddb9-41f8-b32e-99fe065d7b96\",\"trace_id\":\"72c5e7e0-897d-4fe8-9870-46360bfaad50\"}\n[2026-05-11 10:25:31] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"adb456f4-ddb9-41f8-b32e-99fe065d7b96\",\"trace_id\":\"72c5e7e0-897d-4fe8-9870-46360bfaad50\"}\n[2026-05-11 10:25:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:33] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:15:00, 2026-05-11 10:20:00] {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:33] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:15:00, 2026-05-11 10:20:00] {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:36] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:20\",\"to\":\"10:25\"} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:36] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:15\",\"to\":\"00:20\"} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:42] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a32adbf6-c09d-4d9c-983f-5be6f0ce6513\",\"trace_id\":\"7986b833-6171-4907-90a7-405a30938b33\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c579e1ac-b1aa-4530-bfbe-446399c34ed7\",\"trace_id\":\"1188f284-932b-4f41-953a-c141ee01e928\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:27:48.421391Z\"} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c579e1ac-b1aa-4530-bfbe-446399c34ed7\",\"trace_id\":\"1188f284-932b-4f41-953a-c141ee01e928\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a32adbf6-c09d-4d9c-983f-5be6f0ce6513\",\"trace_id\":\"7986b833-6171-4907-90a7-405a30938b33\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:54] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ceb0c5d9-7814-4b15-b86b-9219d218ff94\",\"trace_id\":\"9ab3de82-63b8-4bcc-b7d0-10b01190b029\"}\n[2026-05-11 10:26:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"ceb0c5d9-7814-4b15-b86b-9219d218ff94\",\"trace_id\":\"9ab3de82-63b8-4bcc-b7d0-10b01190b029\"}\n[2026-05-11 10:26:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ceb0c5d9-7814-4b15-b86b-9219d218ff94\",\"trace_id\":\"9ab3de82-63b8-4bcc-b7d0-10b01190b029\"}\n[2026-05-11 10:26:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d46ad7d9-64f7-43a0-9684-4b23ef6c811b\",\"trace_id\":\"2b474f1c-c197-4566-9bbc-1808f88f2fff\"}\n[2026-05-11 10:26:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d46ad7d9-64f7-43a0-9684-4b23ef6c811b\",\"trace_id\":\"2b474f1c-c197-4566-9bbc-1808f88f2fff\"}\n[2026-05-11 10:26:12] local.NOTICE: Monitoring start {\"correlation_id\":\"560c552d-93de-4e0b-b2df-732961322f44\",\"trace_id\":\"234c1c50-a070-4bda-be52-b55d2928120b\"}\n[2026-05-11 10:26:12] local.NOTICE: Monitoring end {\"correlation_id\":\"560c552d-93de-4e0b-b2df-732961322f44\",\"trace_id\":\"234c1c50-a070-4bda-be52-b55d2928120b\"}\n[2026-05-11 10:26:14] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b06f3e7a-d18d-4f1a-bc13-eab0a626e8fc\",\"trace_id\":\"d178ac51-c26f-41af-952c-892796fa9a7d\"}\n[2026-05-11 10:26:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b06f3e7a-d18d-4f1a-bc13-eab0a626e8fc\",\"trace_id\":\"d178ac51-c26f-41af-952c-892796fa9a7d\"}\n[2026-05-11 10:26:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:17] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:17] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:19] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:24:00, 2026-05-11 10:26:00] {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:20] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:24:00, 2026-05-11 10:26:00] {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"bef61b4f-9a53-43fd-a038-f57aea589c46\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"bef61b4f-9a53-43fd-a038-f57aea589c46\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24406712,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":109.34,\"usage\":24468752,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24426968,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [BatchSyncRedisService] Reset meta batch {\"config_id\":2,\"object_type\":\"company\",\"event_type\":\"all\",\"meta_key\":\"batch_sync_company:meta:2:all\",\"reset_at\":1778495184} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [WebhookSyncBatchProcessor] Batch processing completed {\"object_type\":\"company\",\"config_id\":2,\"total_dispatched\":1,\"batches_dispatched\":1} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.5,\"average_seconds_per_request\":0.5} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":548.45} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":747.22,\"usage\":24492704,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [ImportAccountBatch] Processing batch {\"crmConfigurationId\":2,\"batchSize\":1} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [HubSpot] Batch fetched companies {\"requested_count\":1,\"returned_count\":1,\"crm_ids\":[\"52628776324\"]} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"52628776324\",\"config_id\":2} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [HubSpot] importAccountBatch timing {\"teamId\":2,\"account_count\":1,\"requested_count\":1,\"not_found_count\":0,\"total_ms\":778,\"fetch_api_ms\":737,\"accounts_loop_ms\":40,\"avg_account_ms\":40,\"slow_accounts_count\":0,\"slow_accounts\":[]} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [ImportAccountBatch] Batch completed {\"crmConfigurationId\":2,\"success\":1,\"failed\":0,\"skipped\":0,\"requested\":1,\"processed\":1,\"duration_ms\":779.26} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24651424,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":51.35,\"usage\":24654912,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24615552,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":30.26,\"usage\":24658496,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4e1f70b0-9d56-410c-9032-413bf9893d77\",\"trace_id\":\"0095fb60-0f43-4f5e-8ac7-20bccd3437be\"}\n[2026-05-11 10:26:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4e1f70b0-9d56-410c-9032-413bf9893d77\",\"trace_id\":\"0095fb60-0f43-4f5e-8ac7-20bccd3437be\"}\n[2026-05-11 10:26:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:34] local.INFO: [EmailSchedule] STARTING Inbox Sync {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:34] local.INFO: [EmailSchedule] FINISHED Inbox Sync {\"host\":\"docker_lamp_1\",\"events\":2} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":59} {\"correlation_id\":\"4f907293-a2ce-4136-b8cb-8d41c4462d35\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 59 due to unauthorized access to the mailbox {\"correlation_id\":\"4f907293-a2ce-4136-b8cb-8d41c4462d35\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":59} {\"correlation_id\":\"4f907293-a2ce-4136-b8cb-8d41c4462d35\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":212} {\"correlation_id\":\"514c7e78-20b5-4f67-bf77-479acd3e08f1\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 212 due to unauthorized access to the mailbox {\"correlation_id\":\"514c7e78-20b5-4f67-bf77-479acd3e08f1\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":212} {\"correlation_id\":\"514c7e78-20b5-4f67-bf77-479acd3e08f1\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":57,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":280.4,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:27:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0fa8e2ca-02d1-445d-8926-f63d538d158c\",\"trace_id\":\"4f40000b-4fd4-4f41-9b87-c3a75f103f0b\"}\n[2026-05-11 10:27:09] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"0fa8e2ca-02d1-445d-8926-f63d538d158c\",\"trace_id\":\"4f40000b-4fd4-4f41-9b87-c3a75f103f0b\"}\n[2026-05-11 10:27:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0fa8e2ca-02d1-445d-8926-f63d538d158c\",\"trace_id\":\"4f40000b-4fd4-4f41-9b87-c3a75f103f0b\"}\n[2026-05-11 10:27:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"68148728-decd-43a7-9a08-87f059dc48f1\",\"trace_id\":\"e22a5080-2fb8-4f67-8416-0b879e20d8a2\"}\n[2026-05-11 10:27:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"68148728-decd-43a7-9a08-87f059dc48f1\",\"trace_id\":\"e22a5080-2fb8-4f67-8416-0b879e20d8a2\"}\n[2026-05-11 10:27:16] local.NOTICE: Monitoring start {\"correlation_id\":\"9cdfbf72-6c1e-4dc4-93ad-64856bbb0cd7\",\"trace_id\":\"81b03f94-7a43-44ba-9a59-eae3cc760b20\"}\n[2026-05-11 10:27:16] local.NOTICE: Monitoring end {\"correlation_id\":\"9cdfbf72-6c1e-4dc4-93ad-64856bbb0cd7\",\"trace_id\":\"81b03f94-7a43-44ba-9a59-eae3cc760b20\"}\n[2026-05-11 10:27:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6f75a1a9-292f-46e3-83d3-14ca3581ddb2\",\"trace_id\":\"909f3358-7a1d-4c9b-bcfb-f59f2e47fd47\"}\n[2026-05-11 10:27:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6f75a1a9-292f-46e3-83d3-14ca3581ddb2\",\"trace_id\":\"909f3358-7a1d-4c9b-bcfb-f59f2e47fd47\"}\n[2026-05-11 10:27:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:21] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:24] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:24] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"7921218f-5c01-44a0-8bfb-c6da1eaf2761\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"40689200-34eb-44dc-8734-2a7e4efe7f82\",\"trace_id\":\"b0f72776-b242-4f70-a188-92fa324dc525\"}\n[2026-05-11 10:28:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"40689200-34eb-44dc-8734-2a7e4efe7f82\",\"trace_id\":\"b0f72776-b242-4f70-a188-92fa324dc525\"}\n[2026-05-11 10:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"40689200-34eb-44dc-8734-2a7e4efe7f82\",\"trace_id\":\"b0f72776-b242-4f70-a188-92fa324dc525\"}\n[2026-05-11 10:28:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a79c351f-f63a-4942-b81a-f71a44ccd709\",\"trace_id\":\"ecfb945c-3c6f-414f-b45f-d17a477e626f\"}\n[2026-05-11 10:28:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a79c351f-f63a-4942-b81a-f71a44ccd709\",\"trace_id\":\"ecfb945c-3c6f-414f-b45f-d17a477e626f\"}\n[2026-05-11 10:28:10] local.NOTICE: Monitoring start {\"correlation_id\":\"49734034-a0b9-4576-a904-b0bfc2c8edf4\",\"trace_id\":\"de775bb9-3038-4bdc-8a4f-6a015c108223\"}\n[2026-05-11 10:28:11] local.NOTICE: Monitoring end {\"correlation_id\":\"49734034-a0b9-4576-a904-b0bfc2c8edf4\",\"trace_id\":\"de775bb9-3038-4bdc-8a4f-6a015c108223\"}\n[2026-05-11 10:28:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a65dee3f-09de-4601-af88-cc9df13d892f\",\"trace_id\":\"7795b9b5-f4d0-4d76-b1db-deb500a9779b\"}\n[2026-05-11 10:28:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a65dee3f-09de-4601-af88-cc9df13d892f\",\"trace_id\":\"7795b9b5-f4d0-4d76-b1db-deb500a9779b\"}\n[2026-05-11 10:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:22] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:22] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:26] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:26:00, 2026-05-11 10:28:00] {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:26] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:26:00, 2026-05-11 10:28:00] {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"7ec2c6bf-ee39-4528-931a-65adba7f71be\",\"trace_id\":\"99692240-2872-4e5c-9bcd-4288a252b7d1\"}\n[2026-05-11 10:28:34] local.NOTICE: Calendar sync start {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"7ec2c6bf-ee39-4528-931a-65adba7f71be\",\"trace_id\":\"99692240-2872-4e5c-9bcd-4288a252b7d1\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 72dca194-9707-4e51-83a1-c87c97dc1800 Correlation ID: b3a75d57-64c2-48ff-a376-2c94d1bab535 Timestamp: 2026-05-11 10:28:36Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:36Z\\\",\\\"trace_id\\\":\\\"72dca194-9707-4e51-83a1-c87c97dc1800\\\",\\\"correlation_id\\\":\\\"b3a75d57-64c2-48ff-a376-2c94d1bab535\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 10d1576d-0c9c-41ab-8f10-d27611d01f00 Correlation ID: 258f8dcc-012b-46af-b572-ac9a9fc203ad Timestamp: 2026-05-11 10:28:37Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:37Z\\\",\\\"trace_id\\\":\\\"10d1576d-0c9c-41ab-8f10-d27611d01f00\\\",\\\"correlation_id\\\":\\\"258f8dcc-012b-46af-b572-ac9a9fc203ad\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Token has been expired or revoked.\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 9d674338-6e76-4e83-aca4-da73b67e1d00 Correlation ID: 3a4aff15-90cc-41a4-9b3f-c5162caec715 Timestamp: 2026-05-11 10:28:38Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:38Z\\\",\\\"trace_id\\\":\\\"9d674338-6e76-4e83-aca4-da73b67e1d00\\\",\\\"correlation_id\\\":\\\"3a4aff15-90cc-41a4-9b3f-c5162caec715\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dc988698-5fac-4412-96aa-bcbd33ff2000 Correlation ID: 475197fc-db2f-4216-98d8-e092ad827d60 Timestamp: 2026-05-11 10:28:39Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:39Z\\\",\\\"trace_id\\\":\\\"dc988698-5fac-4412-96aa-bcbd33ff2000\\\",\\\"correlation_id\\\":\\\"475197fc-db2f-4216-98d8-e092ad827d60\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 4e60d43e-f26e-46ce-96df-0f7e57702500 Correlation ID: bb550866-1814-4ebf-9ff2-3916798900b9 Timestamp: 2026-05-11 10:28:39Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:39Z\\\",\\\"trace_id\\\":\\\"4e60d43e-f26e-46ce-96df-0f7e57702500\\\",\\\"correlation_id\\\":\\\"bb550866-1814-4ebf-9ff2-3916798900b9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1775683749,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-04-08 22:58:34\"}}} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCLlvcOB4kXlhlC7KgH1SnZwTrZ3faZv1fXPQqJhxe_L9AxWWlb-wASsjGiiWlhsBUg9MFb3ZdlAYerVV_ZirRPbsKWCxEXhybD90arJmok_M4ecGFUQ9_BIGu-c6RAnJy2TRKZ7gPTsJi_8TGceGAuqimlhm4G4mjDLvYVVwImjjU7M3xJvUzL47dLOGNTJCww.k1TST0VEYCgbFOkwa3ysYMi100FtVfkzfqlXLnV6gPg\",\"last_sync\":\"2026-05-11 06:13:36\",\"dateMode\":\"daily\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0465eb00-6e46-4718-af63-3e39a581fe31\",\"trace_id\":\"7410dc20-61f5-466f-b207-731d3b5a8f9c\"}\n[2026-05-11 10:29:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"0465eb00-6e46-4718-af63-3e39a581fe31\",\"trace_id\":\"7410dc20-61f5-466f-b207-731d3b5a8f9c\"}\n[2026-05-11 10:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0465eb00-6e46-4718-af63-3e39a581fe31\",\"trace_id\":\"7410dc20-61f5-466f-b207-731d3b5a8f9c\"}\n[2026-05-11 10:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"54350d90-7959-4b7e-b190-24ca14a2e28f\",\"trace_id\":\"90339d05-d9db-4a22-ac90-bcf8d2855cb1\"}\n[2026-05-11 10:29:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"54350d90-7959-4b7e-b190-24ca14a2e28f\",\"trace_id\":\"90339d05-d9db-4a22-ac90-bcf8d2855cb1\"}\n[2026-05-11 10:29:08] local.NOTICE: Monitoring start {\"correlation_id\":\"6cb6c4e6-5b94-4a35-95b9-d0da3e00b0f4\",\"trace_id\":\"d035104f-576f-40f5-8a4a-9c8b0e339b74\"}\n[2026-05-11 10:29:08] local.NOTICE: Monitoring end {\"correlation_id\":\"6cb6c4e6-5b94-4a35-95b9-d0da3e00b0f4\",\"trace_id\":\"d035104f-576f-40f5-8a4a-9c8b0e339b74\"}\n[2026-05-11 10:29:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"17f41c15-8b7a-4042-b2cf-b4989d7bec56\",\"trace_id\":\"ebf0f7cf-dccb-41de-a5c3-540cbd34be35\"}\n[2026-05-11 10:29:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"17f41c15-8b7a-4042-b2cf-b4989d7bec56\",\"trace_id\":\"ebf0f7cf-dccb-41de-a5c3-540cbd34be35\"}\n[2026-05-11 10:29:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:29:11] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:29:11] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:29:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:30:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2aba99d8-c58b-447d-9817-1a5a9504fef5\",\"trace_id\":\"e2ffb579-ceae-406d-9a7f-08b872c99d53\"}\n[2026-05-11 10:30:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"2aba99d8-c58b-447d-9817-1a5a9504fef5\",\"trace_id\":\"e2ffb579-ceae-406d-9a7f-08b872c99d53\"}\n[2026-05-11 10:30:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2aba99d8-c58b-447d-9817-1a5a9504fef5\",\"trace_id\":\"e2ffb579-ceae-406d-9a7f-08b872c99d53\"}\n[2026-05-11 10:30:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e2cf0fc5-2d3f-46d9-b39d-a9beab9df260\",\"trace_id\":\"c5fda48b-3876-47c1-8186-64cce7e053eb\"}\n[2026-05-11 10:30:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e2cf0fc5-2d3f-46d9-b39d-a9beab9df260\",\"trace_id\":\"c5fda48b-3876-47c1-8186-64cce7e053eb\"}\n[2026-05-11 10:30:10] local.NOTICE: Monitoring start {\"correlation_id\":\"4ae14f41-e60e-4136-8839-1d1fd0daaf12\",\"trace_id\":\"1afb6ea3-fcc0-41bc-836c-504edc28e986\"}\n[2026-05-11 10:30:10] local.NOTICE: Monitoring end {\"correlation_id\":\"4ae14f41-e60e-4136-8839-1d1fd0daaf12\",\"trace_id\":\"1afb6ea3-fcc0-41bc-836c-504edc28e986\"}\n[2026-05-11 10:30:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"bd56adee-a96c-4f21-81ec-b7543cb5492b\",\"trace_id\":\"968bf9e5-04a2-4236-8db5-5ec33bd01f07\"}\n[2026-05-11 10:30:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"bd56adee-a96c-4f21-81ec-b7543cb5492b\",\"trace_id\":\"968bf9e5-04a2-4236-8db5-5ec33bd01f07\"}\n[2026-05-11 10:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:13] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:13] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:28:00, 2026-05-11 10:30:00] {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:28:00, 2026-05-11 10:30:00] {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"02dff32b-488e-43e8-ac22-709dea182f79\",\"trace_id\":\"4bb34b12-3c2c-4705-bf96-7c52086432be\"}\n[2026-05-11 10:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"02dff32b-488e-43e8-ac22-709dea182f79\",\"trace_id\":\"4bb34b12-3c2c-4705-bf96-7c52086432be\"}\n[2026-05-11 10:30:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a5991b76-81d9-4f65-aaac-699d006f1042\",\"trace_id\":\"1b29b5dc-ceae-4cee-84de-47550a07d9d4\"}\n[2026-05-11 10:30:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a5991b76-81d9-4f65-aaac-699d006f1042\",\"trace_id\":\"1b29b5dc-ceae-4cee-84de-47550a07d9d4\"}\n[2026-05-11 10:30:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"381abaee-2e1c-4372-a476-e2eae2dca7ce\",\"trace_id\":\"048ab219-e61e-4a62-8bd7-6f50ba180460\"}\n[2026-05-11 10:30:21] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"381abaee-2e1c-4372-a476-e2eae2dca7ce\",\"trace_id\":\"048ab219-e61e-4a62-8bd7-6f50ba180460\"}\n[2026-05-11 10:30:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"381abaee-2e1c-4372-a476-e2eae2dca7ce\",\"trace_id\":\"048ab219-e61e-4a62-8bd7-6f50ba180460\"}\n[2026-05-11 10:30:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:24] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:20:00, 2026-05-11 10:25:00] {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:24] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:20:00, 2026-05-11 10:25:00] {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:25] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:25\",\"to\":\"10:30\"} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:25] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:20\",\"to\":\"00:25\"} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:27] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"82ba3881-bffd-4764-96dd-3d22f9b2a3c9\",\"trace_id\":\"ec98b699-f5f0-4635-9ab1-f8bd359a0ab4\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"07e31516-7a25-4b7b-99b5-f4d215235639\",\"trace_id\":\"bd9719aa-9cb7-49a1-abcd-e22fb29d7ecb\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:32:33.541224Z\"} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"82ba3881-bffd-4764-96dd-3d22f9b2a3c9\",\"trace_id\":\"ec98b699-f5f0-4635-9ab1-f8bd359a0ab4\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"07e31516-7a25-4b7b-99b5-f4d215235639\",\"trace_id\":\"bd9719aa-9cb7-49a1-abcd-e22fb29d7ecb\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:38] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ecbaf403-a353-439c-aa9a-8223c91e98a8\",\"trace_id\":\"1d352c76-5c34-4632-9bab-ec97702746aa\"}\n[2026-05-11 10:30:38] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ecbaf403-a353-439c-aa9a-8223c91e98a8\",\"trace_id\":\"1d352c76-5c34-4632-9bab-ec97702746aa\"}\n[2026-05-11 10:30:39] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812688,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812689,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812690,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812691,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812692,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812693,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b12822e6-6528-42d6-998c-8bb26e197d8e\",\"trace_id\":\"577073db-3d72-41ba-ba6c-7a6952649f23\"}\n[2026-05-11 10:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b12822e6-6528-42d6-998c-8bb26e197d8e\",\"trace_id\":\"577073db-3d72-41ba-ba6c-7a6952649f23\"}\n[2026-05-11 10:30:45] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.ALERT: [SyncActivity] Failed {\"import_id\":812688,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Social account for Salesforce cannot be found. Please login to Jiminny to connect.\",\"file\":\"/home/jiminny/app/Services/Crm/BaseService.php\",\"line\":646} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.ALERT: [SyncActivity] Failed {\"import_id\":812689,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.ALERT: [SyncActivity] Failed {\"import_id\":812690,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.ALERT: [SyncActivity] Failed {\"import_id\":812691,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e9e81669-de7e-44a6-948e-fbaf5cebc63b\",\"trace_id\":\"41d48720-ec10-4f33-94d2-c73160baecca\"}\n[2026-05-11 10:30:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e9e81669-de7e-44a6-948e-fbaf5cebc63b\",\"trace_id\":\"41d48720-ec10-4f33-94d2-c73160baecca\"}\n[2026-05-11 10:30:47] local.ALERT: [SyncActivity] Failed {\"import_id\":812692,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SyncActivity] Start {\"import_id\":812693,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-11 10:14:00\",\"to\":\"2026-05-11 10:30:00\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:48] local.INFO: [SyncActivity] End {\"import_id\":812693,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:48] local.INFO: [SyncActivity] Memory usage {\"import_id\":812693,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":27211224,\"memory_real_usage\":65011712,\"pid\":62066} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fa96f49d-52b5-4148-9132-e4e06f25f718\",\"trace_id\":\"16188812-4089-42eb-93b1-1acc50370f56\"}\n[2026-05-11 10:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fa96f49d-52b5-4148-9132-e4e06f25f718\",\"trace_id\":\"16188812-4089-42eb-93b1-1acc50370f56\"}\n[2026-05-11 10:30:52] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:53] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:53] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f36d88f7-e68e-4e33-ae1b-8cff0800fd43\",\"trace_id\":\"a8818078-09e1-42fc-b8fb-767f172228bd\"}\n[2026-05-11 10:31:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"f36d88f7-e68e-4e33-ae1b-8cff0800fd43\",\"trace_id\":\"a8818078-09e1-42fc-b8fb-767f172228bd\"}\n[2026-05-11 10:31:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f36d88f7-e68e-4e33-ae1b-8cff0800fd43\",\"trace_id\":\"a8818078-09e1-42fc-b8fb-767f172228bd\"}\n[2026-05-11 10:31:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f38ba408-a4ad-45de-810a-b180a32b02be\",\"trace_id\":\"16fc212f-055e-4cf4-916c-2400e311426d\"}\n[2026-05-11 10:31:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f38ba408-a4ad-45de-810a-b180a32b02be\",\"trace_id\":\"16fc212f-055e-4cf4-916c-2400e311426d\"}\n[2026-05-11 10:31:11] local.NOTICE: Monitoring start {\"correlation_id\":\"38529cdf-db5d-486c-abe3-974e92c4eaa5\",\"trace_id\":\"61b274d5-6524-48ff-b90d-192ba1b785a5\"}\n[2026-05-11 10:31:11] local.NOTICE: Monitoring end {\"correlation_id\":\"38529cdf-db5d-486c-abe3-974e92c4eaa5\",\"trace_id\":\"61b274d5-6524-48ff-b90d-192ba1b785a5\"}\n[2026-05-11 10:31:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"eaecf0f8-8839-496f-a8f7-ae98023db10b\",\"trace_id\":\"e78bc97b-95c9-49da-a246-4478b6548da3\"}\n[2026-05-11 10:31:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"eaecf0f8-8839-496f-a8f7-ae98023db10b\",\"trace_id\":\"e78bc97b-95c9-49da-a246-4478b6548da3\"}\n[2026-05-11 10:31:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:15] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:15] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8d9db40e-4c42-47db-87e4-d37956e23b49\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8d9db40e-4c42-47db-87e4-d37956e23b49\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24619888,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":231.27} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":247.33,\"usage\":24703856,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24681856,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":5.67,\"usage\":24692584,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24650088,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":13.16,\"usage\":24669792,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24630472,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":18.34,\"usage\":24666208,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":189.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:32:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"99ed83ef-ed2e-4a1b-b555-347028040d09\",\"trace_id\":\"1e916484-3166-436d-ab5e-477ef647ac93\"}\n[2026-05-11 10:32:17] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"99ed83ef-ed2e-4a1b-b555-347028040d09\",\"trace_id\":\"1e916484-3166-436d-ab5e-477ef647ac93\"}\n[2026-05-11 10:32:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"99ed83ef-ed2e-4a1b-b555-347028040d09\",\"trace_id\":\"1e916484-3166-436d-ab5e-477ef647ac93\"}\n[2026-05-11 10:32:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ff92f4cc-9fa1-48f4-8132-e7ad945cbc0f\",\"trace_id\":\"30333ea5-961b-48cd-b5db-60a2f101baaa\"}\n[2026-05-11 10:32:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ff92f4cc-9fa1-48f4-8132-e7ad945cbc0f\",\"trace_id\":\"30333ea5-961b-48cd-b5db-60a2f101baaa\"}\n[2026-05-11 10:32:28] local.NOTICE: Monitoring start {\"correlation_id\":\"8770e909-fa53-41ff-92a2-476d237422fd\",\"trace_id\":\"e3a38637-5e1f-46c9-b0cd-221f7c2133d5\"}\n[2026-05-11 10:32:28] local.NOTICE: Monitoring end {\"correlation_id\":\"8770e909-fa53-41ff-92a2-476d237422fd\",\"trace_id\":\"e3a38637-5e1f-46c9-b0cd-221f7c2133d5\"}\n[2026-05-11 10:32:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c36b230c-d92e-4f13-b57c-69b13f36794c\",\"trace_id\":\"ddf0dc75-7947-47f4-afe2-5ce286f8925e\"}\n[2026-05-11 10:32:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c36b230c-d92e-4f13-b57c-69b13f36794c\",\"trace_id\":\"ddf0dc75-7947-47f4-afe2-5ce286f8925e\"}\n[2026-05-11 10:32:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:39] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:40] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:44] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:30:00, 2026-05-11 10:32:00] {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:44] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:30:00, 2026-05-11 10:32:00] {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"95652e88-1c5d-45a7-b3c0-2bab2f761d8a\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:33:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"7af2c981-e735-4da9-83e1-79395f195e41\",\"trace_id\":\"31cad47b-63cf-48ba-a06f-98ecbaa5c683\"}\n[2026-05-11 10:33:11] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"7af2c981-e735-4da9-83e1-79395f195e41\",\"trace_id\":\"31cad47b-63cf-48ba-a06f-98ecbaa5c683\"}\n[2026-05-11 10:33:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"7af2c981-e735-4da9-83e1-79395f195e41\",\"trace_id\":\"31cad47b-63cf-48ba-a06f-98ecbaa5c683\"}\n[2026-05-11 10:33:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e9ca3026-0b79-43b7-b8a0-de3a719f35d7\",\"trace_id\":\"a594cb67-5fee-4b2e-9acd-ac8c20585296\"}\n[2026-05-11 10:33:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e9ca3026-0b79-43b7-b8a0-de3a719f35d7\",\"trace_id\":\"a594cb67-5fee-4b2e-9acd-ac8c20585296\"}\n[2026-05-11 10:33:18] local.NOTICE: Monitoring start {\"correlation_id\":\"accf51c2-9f23-46e6-b225-198a661828b3\",\"trace_id\":\"0e5ff218-5456-490f-8d9e-476a4be1dd3e\"}\n[2026-05-11 10:33:18] local.NOTICE: Monitoring end {\"correlation_id\":\"accf51c2-9f23-46e6-b225-198a661828b3\",\"trace_id\":\"0e5ff218-5456-490f-8d9e-476a4be1dd3e\"}\n[2026-05-11 10:33:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ee83ff3f-cb13-4c3e-89c9-3b9d5a1121da\",\"trace_id\":\"42bb740c-d4d6-4ae4-9208-656aca0b28ed\"}\n[2026-05-11 10:33:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ee83ff3f-cb13-4c3e-89c9-3b9d5a1121da\",\"trace_id\":\"42bb740c-d4d6-4ae4-9208-656aca0b28ed\"}\n[2026-05-11 10:33:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:26] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:26] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3138b4af-7214-4df7-9c3f-aaafd5a012ad\",\"trace_id\":\"dadba1f4-af42-4319-8063-485e433702b9\"}\n[2026-05-11 10:33:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3138b4af-7214-4df7-9c3f-aaafd5a012ad\",\"trace_id\":\"dadba1f4-af42-4319-8063-485e433702b9\"}\n[2026-05-11 10:34:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"098f3374-2c1a-469b-98b3-1ff77b1b64ec\",\"trace_id\":\"330e4f70-0ca9-4c7a-bbc4-8b8939006f61\"}\n[2026-05-11 10:34:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"098f3374-2c1a-469b-98b3-1ff77b1b64ec\",\"trace_id\":\"330e4f70-0ca9-4c7a-bbc4-8b8939006f61\"}\n[2026-05-11 10:34:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"098f3374-2c1a-469b-98b3-1ff77b1b64ec\",\"trace_id\":\"330e4f70-0ca9-4c7a-bbc4-8b8939006f61\"}\n[2026-05-11 10:34:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5fd2648d-1ba5-4388-b14c-c57cd7ee1a7a\",\"trace_id\":\"1534e514-dbde-4964-ae1f-4163ec21def6\"}\n[2026-05-11 10:34:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5fd2648d-1ba5-4388-b14c-c57cd7ee1a7a\",\"trace_id\":\"1534e514-dbde-4964-ae1f-4163ec21def6\"}\n[2026-05-11 10:34:10] local.NOTICE: Monitoring start {\"correlation_id\":\"b8e36a3e-e2c5-42cc-a849-e27ab98e2880\",\"trace_id\":\"feddd752-d33b-4ce0-ac4d-21f1064646e5\"}\n[2026-05-11 10:34:10] local.NOTICE: Monitoring end {\"correlation_id\":\"b8e36a3e-e2c5-42cc-a849-e27ab98e2880\",\"trace_id\":\"feddd752-d33b-4ce0-ac4d-21f1064646e5\"}\n[2026-05-11 10:34:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3e7afa7f-cf30-4149-b943-0c33e3a5c7c5\",\"trace_id\":\"1389c85d-12c9-49b3-94d9-af4ecf2efb81\"}\n[2026-05-11 10:34:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3e7afa7f-cf30-4149-b943-0c33e3a5c7c5\",\"trace_id\":\"1389c85d-12c9-49b3-94d9-af4ecf2efb81\"}\n[2026-05-11 10:34:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:14] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:14] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:34:19] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:32:00, 2026-05-11 10:34:00] {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:34:20] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:32:00, 2026-05-11 10:34:00] {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:34:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:35:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"72e15b11-c609-4153-bf9f-e4662059eb0e\",\"trace_id\":\"4d66b5da-2b77-4f3c-a1da-1a1c68c19c50\"}\n[2026-05-11 10:35:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"72e15b11-c609-4153-bf9f-e4662059eb0e\",\"trace_id\":\"4d66b5da-2b77-4f3c-a1da-1a1c68c19c50\"}\n[2026-05-11 10:35:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"72e15b11-c609-4153-bf9f-e4662059eb0e\",\"trace_id\":\"4d66b5da-2b77-4f3c-a1da-1a1c68c19c50\"}\n[2026-05-11 10:35:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b1ea8d2e-5708-4573-bf74-1464b7c44d08\",\"trace_id\":\"03dd2361-69c0-4740-b422-de6283642688\"}\n[2026-05-11 10:35:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b1ea8d2e-5708-4573-bf74-1464b7c44d08\",\"trace_id\":\"03dd2361-69c0-4740-b422-de6283642688\"}\n[2026-05-11 10:35:09] local.NOTICE: Monitoring start {\"correlation_id\":\"43feb1c1-6f6b-471f-97b2-ef3fc9ad29ab\",\"trace_id\":\"eb84abda-acdc-4735-becf-e37e580b0144\"}\n[2026-05-11 10:35:09] local.NOTICE: Monitoring end {\"correlation_id\":\"43feb1c1-6f6b-471f-97b2-ef3fc9ad29ab\",\"trace_id\":\"eb84abda-acdc-4735-becf-e37e580b0144\"}\n[2026-05-11 10:35:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ac80bb04-c088-44ae-94aa-08f301d989e5\",\"trace_id\":\"b6c276eb-6d35-4549-8885-62bb13d0fa9f\"}\n[2026-05-11 10:35:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ac80bb04-c088-44ae-94aa-08f301d989e5\",\"trace_id\":\"b6c276eb-6d35-4549-8885-62bb13d0fa9f\"}\n[2026-05-11 10:35:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8d3171b8-b09b-42d3-92df-98abf8692ebd\",\"trace_id\":\"141b26bb-770c-4730-ad66-f3a3ad84c825\"}\n[2026-05-11 10:35:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8d3171b8-b09b-42d3-92df-98abf8692ebd\",\"trace_id\":\"141b26bb-770c-4730-ad66-f3a3ad84c825\"}\n[2026-05-11 10:35:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d7bec853-b7c7-4ac4-99bc-24b2c0f89e94\",\"trace_id\":\"9a5d8a19-7529-4ed1-b6de-2780141ed4f1\"}\n[2026-05-11 10:35:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d7bec853-b7c7-4ac4-99bc-24b2c0f89e94\",\"trace_id\":\"9a5d8a19-7529-4ed1-b6de-2780141ed4f1\"}\n[2026-05-11 10:35:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a3334550-1eb7-45ae-9923-b190499518e7\",\"trace_id\":\"6ad3fbaf-f20d-4a1d-9e47-06f0dbd4e3ad\"}\n[2026-05-11 10:35:21] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"a3334550-1eb7-45ae-9923-b190499518e7\",\"trace_id\":\"6ad3fbaf-f20d-4a1d-9e47-06f0dbd4e3ad\"}\n[2026-05-11 10:35:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a3334550-1eb7-45ae-9923-b190499518e7\",\"trace_id\":\"6ad3fbaf-f20d-4a1d-9e47-06f0dbd4e3ad\"}\n[2026-05-11 10:35:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:25] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:25:00, 2026-05-11 10:30:00] {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:25] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:25:00, 2026-05-11 10:30:00] {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:28] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:30\",\"to\":\"10:35\"} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:28] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:25\",\"to\":\"00:30\"} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:33] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"20844949-5e84-4735-b2d0-162745055e3d\",\"trace_id\":\"f673cac2-b390-421f-85c6-53b63c6d54e6\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"96255b3e-9e6c-40fa-b8c5-2ea047f63c25\",\"trace_id\":\"d1558e0d-cec5-4629-88da-c68477454a63\"}\n[2026-05-11 10:35:40] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:40] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:40] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:37:40.730010Z\"} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"96255b3e-9e6c-40fa-b8c5-2ea047f63c25\",\"trace_id\":\"d1558e0d-cec5-4629-88da-c68477454a63\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"20844949-5e84-4735-b2d0-162745055e3d\",\"trace_id\":\"f673cac2-b390-421f-85c6-53b63c6d54e6\"}\n[2026-05-11 10:35:41] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:46] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:51] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"646573be-6ee2-4c9a-895f-18cc290289ee\",\"trace_id\":\"f45ddc5e-217c-44cf-818a-8e19115ba801\"}\n[2026-05-11 10:36:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"646573be-6ee2-4c9a-895f-18cc290289ee\",\"trace_id\":\"f45ddc5e-217c-44cf-818a-8e19115ba801\"}\n[2026-05-11 10:36:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"646573be-6ee2-4c9a-895f-18cc290289ee\",\"trace_id\":\"f45ddc5e-217c-44cf-818a-8e19115ba801\"}\n[2026-05-11 10:36:06] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"45c6bc69-8367-4c77-b987-59184ca3a28f\",\"trace_id\":\"65f717ea-0fba-4a9b-991a-5997e0f8f9b0\"}\n[2026-05-11 10:36:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"45c6bc69-8367-4c77-b987-59184ca3a28f\",\"trace_id\":\"65f717ea-0fba-4a9b-991a-5997e0f8f9b0\"}\n[2026-05-11 10:36:09] local.NOTICE: Monitoring start {\"correlation_id\":\"a0611974-bf3b-409d-9f83-642f4abc0528\",\"trace_id\":\"f3d77eda-6e9f-4add-b728-61e6473902fc\"}\n[2026-05-11 10:36:09] local.NOTICE: Monitoring end {\"correlation_id\":\"a0611974-bf3b-409d-9f83-642f4abc0528\",\"trace_id\":\"f3d77eda-6e9f-4add-b728-61e6473902fc\"}\n[2026-05-11 10:36:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8f7dcbae-1394-4d35-9ab4-9bd99edda2a7\",\"trace_id\":\"2d5ba640-0e5c-406f-9ec4-7b6c3f8088c0\"}\n[2026-05-11 10:36:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8f7dcbae-1394-4d35-9ab4-9bd99edda2a7\",\"trace_id\":\"2d5ba640-0e5c-406f-9ec4-7b6c3f8088c0\"}\n[2026-05-11 10:36:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:34:00, 2026-05-11 10:36:00] {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:34:00, 2026-05-11 10:36:00] {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2bafa5b7-2847-4162-b0e5-d7568645a4ff\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2bafa5b7-2847-4162-b0e5-d7568645a4ff\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24627560,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"refreshToken\":\"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86\",\"state\":\"connected\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b713b8da-2776-4938-8ee3-f0fbf55283c9\",\"trace_id\":\"1d932c6b-6fad-465f-b102-c442cd814509\"}\n[2026-05-11 10:36:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b713b8da-2776-4938-8ee3-f0fbf55283c9\",\"trace_id\":\"1d932c6b-6fad-465f-b102-c442cd814509\"}\n[2026-05-11 10:36:17] local.INFO: [SocialAccountService] Token refreshed {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"state\":\"connected\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.25,\"average_seconds_per_request\":0.25} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":277.55} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":1348.99,\"usage\":24981096,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24955832,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":40.17,\"usage\":24956128,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24913632,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":357.18,\"usage\":24929752,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24890392,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":36.73,\"usage\":24933336,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:27] local.INFO: [EmailSchedule] STARTING Inbox Sync {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:28] local.INFO: [EmailSchedule] FINISHED Inbox Sync {\"host\":\"docker_lamp_1\",\"events\":2} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":59} {\"correlation_id\":\"5b391868-ba48-4b0d-8aa8-b65842b802c5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 59 due to unauthorized access to the mailbox {\"correlation_id\":\"5b391868-ba48-4b0d-8aa8-b65842b802c5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":59} {\"correlation_id\":\"5b391868-ba48-4b0d-8aa8-b65842b802c5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":212} {\"correlation_id\":\"cf7b2fe7-fb62-4202-956b-09a6784b3bc5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 212 due to unauthorized access to the mailbox {\"correlation_id\":\"cf7b2fe7-fb62-4202-956b-09a6784b3bc5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":212} {\"correlation_id\":\"cf7b2fe7-fb62-4202-956b-09a6784b3bc5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:36] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:36] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":57,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":190.5,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a6bf12a7-3d44-4661-9fec-f5ab6d89bcf6\",\"trace_id\":\"f56da488-8a51-443c-a69b-799615697e25\"}\n[2026-05-11 10:37:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"a6bf12a7-3d44-4661-9fec-f5ab6d89bcf6\",\"trace_id\":\"f56da488-8a51-443c-a69b-799615697e25\"}\n[2026-05-11 10:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a6bf12a7-3d44-4661-9fec-f5ab6d89bcf6\",\"trace_id\":\"f56da488-8a51-443c-a69b-799615697e25\"}\n[2026-05-11 10:37:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c831237f-7638-4919-b5a1-785d5aaeee99\",\"trace_id\":\"11fac131-feb0-443c-ba9f-e5215a104d04\"}\n[2026-05-11 10:37:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c831237f-7638-4919-b5a1-785d5aaeee99\",\"trace_id\":\"11fac131-feb0-443c-ba9f-e5215a104d04\"}\n[2026-05-11 10:37:10] local.NOTICE: Monitoring start {\"correlation_id\":\"3285ad9f-3fed-491c-a8dc-3737343e83ea\",\"trace_id\":\"77a84391-a532-4d0a-9847-b862f29ddd75\"}\n[2026-05-11 10:37:10] local.NOTICE: Monitoring end {\"correlation_id\":\"3285ad9f-3fed-491c-a8dc-3737343e83ea\",\"trace_id\":\"77a84391-a532-4d0a-9847-b862f29ddd75\"}\n[2026-05-11 10:37:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fbd5efb3-e8a5-4e05-a201-40e67d8c5d57\",\"trace_id\":\"9aebad16-8ed6-4d38-bcd5-04f2875cbde3\"}\n[2026-05-11 10:37:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fbd5efb3-e8a5-4e05-a201-40e67d8c5d57\",\"trace_id\":\"9aebad16-8ed6-4d38-bcd5-04f2875cbde3\"}\n[2026-05-11 10:37:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:14] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:14] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:16] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:16] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:18] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"a939b046-9e38-485d-afb9-a17b4b7907f4\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"70310051-3a12-46e9-84a4-89c72f743167\",\"trace_id\":\"a37be552-6047-475b-951a-06ff4a9507f5\"}\n[2026-05-11 10:37:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"70310051-3a12-46e9-84a4-89c72f743167\",\"trace_id\":\"a37be552-6047-475b-951a-06ff4a9507f5\"}\n[2026-05-11 10:38:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"46b097b8-0b96-4d90-8a93-539a384c5823\",\"trace_id\":\"74d4d667-dc86-448e-a692-45ff5cb453cd\"}\n[2026-05-11 10:38:04] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"46b097b8-0b96-4d90-8a93-539a384c5823\",\"trace_id\":\"74d4d667-dc86-448e-a692-45ff5cb453cd\"}\n[2026-05-11 10:38:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"46b097b8-0b96-4d90-8a93-539a384c5823\",\"trace_id\":\"74d4d667-dc86-448e-a692-45ff5cb453cd\"}\n[2026-05-11 10:38:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3a67375e-c351-4ae5-82bc-948e778e0048\",\"trace_id\":\"d2248abd-029a-44e7-9157-58a0622bfc10\"}\n[2026-05-11 10:38:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3a67375e-c351-4ae5-82bc-948e778e0048\",\"trace_id\":\"d2248abd-029a-44e7-9157-58a0622bfc10\"}\n[2026-05-11 10:38:11] local.NOTICE: Monitoring start {\"correlation_id\":\"036a52a0-2c7b-4b54-a54d-01900cc57738\",\"trace_id\":\"aa5f7049-6f54-4d09-a774-be41c55079b6\"}\n[2026-05-11 10:38:11] local.NOTICE: Monitoring end {\"correlation_id\":\"036a52a0-2c7b-4b54-a54d-01900cc57738\",\"trace_id\":\"aa5f7049-6f54-4d09-a774-be41c55079b6\"}\n[2026-05-11 10:38:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ac59669b-fbbb-4d3c-975b-b48d7e219deb\",\"trace_id\":\"ac455aaf-2475-4e43-8532-720d4707b298\"}\n[2026-05-11 10:38:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ac59669b-fbbb-4d3c-975b-b48d7e219deb\",\"trace_id\":\"ac455aaf-2475-4e43-8532-720d4707b298\"}\n[2026-05-11 10:38:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:15] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:15] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:18] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:36:00, 2026-05-11 10:38:00] {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:18] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:36:00, 2026-05-11 10:38:00] {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fef6e1aa-1b8b-46da-b451-cf6ab0fc7698\",\"trace_id\":\"e8a43881-fcaf-40af-80b9-afe0bbcbaac1\"}\n[2026-05-11 10:38:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fef6e1aa-1b8b-46da-b451-cf6ab0fc7698\",\"trace_id\":\"e8a43881-fcaf-40af-80b9-afe0bbcbaac1\"}\n[2026-05-11 10:39:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f6f145bd-ff6f-43b8-9428-a1dfacda358f\",\"trace_id\":\"82b82fdf-25bf-445c-a495-961fb5037236\"}\n[2026-05-11 10:39:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"f6f145bd-ff6f-43b8-9428-a1dfacda358f\",\"trace_id\":\"82b82fdf-25bf-445c-a495-961fb5037236\"}\n[2026-05-11 10:39:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f6f145bd-ff6f-43b8-9428-a1dfacda358f\",\"trace_id\":\"82b82fdf-25bf-445c-a495-961fb5037236\"}\n[2026-05-11 10:39:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"61cd5d9f-ca83-40ba-bcf1-828523d60cd9\",\"trace_id\":\"b713000b-147e-48f1-887e-f230ec0cb18a\"}\n[2026-05-11 10:39:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"61cd5d9f-ca83-40ba-bcf1-828523d60cd9\",\"trace_id\":\"b713000b-147e-48f1-887e-f230ec0cb18a\"}\n[2026-05-11 10:39:11] local.NOTICE: Monitoring start {\"correlation_id\":\"30a5fa99-8b11-4637-a67e-25437db0dec1\",\"trace_id\":\"b92ae3ad-cbf2-4323-9146-cea7de2e9b0b\"}\n[2026-05-11 10:39:11] local.NOTICE: Monitoring end {\"correlation_id\":\"30a5fa99-8b11-4637-a67e-25437db0dec1\",\"trace_id\":\"b92ae3ad-cbf2-4323-9146-cea7de2e9b0b\"}\n[2026-05-11 10:39:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"40697c1c-e78d-4166-991a-23dee13df5ac\",\"trace_id\":\"7adaa4f7-a908-4fbc-b2a9-497c6f2c8f73\"}\n[2026-05-11 10:39:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"40697c1c-e78d-4166-991a-23dee13df5ac\",\"trace_id\":\"7adaa4f7-a908-4fbc-b2a9-497c6f2c8f73\"}\n[2026-05-11 10:39:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:16] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:16] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.ERROR: [Aircall] Re-activating webhooks failed {\"team_id\":1,\"reason\":\"{\\\"message\\\":\\\"Forbidden\\\"}\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:22] local.INFO: [RetryFailedDownloads] Starting {\"options\":{\"from\":null,\"to\":null,\"help\":false,\"silent\":false,\"quiet\":false,\"verbose\":false,\"version\":false,\"ansi\":null,\"no-interaction\":false,\"env\":null}} {\"correlation_id\":\"0090d89b-5dff-472f-a7db-3bffabdf1eb7\",\"trace_id\":\"3c2e9b6b-2e7f-4460-9aa8-e287cdb20dfe\"}","depth":4,"bounds":{"left":0.35006648,"top":0.10614525,"width":0.6499335,"height":0.89385474},"on_screen":true,"value":"[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-5 (truncated...)\n\"} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"f0becb3b-1f4f-4fb3-a311-9056fd2ae449\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"78f847cf-6495-4054-b3d4-e179a133bd42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613840,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613840,\"participants\":[{\"id\":1001764,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001765,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613840,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613840,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613840} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613840,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613840,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"14d1f2d6-526c-4a7b-9dbe-f310d28baff2\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613833,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613833,\"participants\":[{\"id\":1001750,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001751,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613833,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613833,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613833} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613833,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613833,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f9846f48-5841-4a71-b500-64b802c67d05\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613827,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613827,\"participants\":[{\"id\":1001734,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001735,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613827,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613827,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613827} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613827,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613827,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d060f13a-e3b7-416c-ac24-ebc305d1fd66\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613826,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613826,\"participants\":[{\"id\":1001732,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001733,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613826,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613826,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613826} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613826,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613826,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613820,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613820,\"participants\":[{\"id\":1001721,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001722,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613820,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613820,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613820} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613820,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613820,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ee78448a-70af-4da3-a3cd-238e2067a49c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613818,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613818,\"participants\":[{\"id\":1001717,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001718,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613818,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613818,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613818} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613818,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613818,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"74704a29-86b2-4b3f-ae73-0e6d4ec1891a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613812,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613812,\"participants\":[{\"id\":1001705,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001706,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613812,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613812,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613812} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613812,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613812,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0698152e-ea7b-46d1-95e4-45730b1aac4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613807,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613807,\"participants\":[{\"id\":1001690,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001691,\"user_id\":null,\"contact_id\":4484,\"lead_id\":null}]} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613807,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4484,\"owner_id\":253} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4484} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4484,\"opportunity_id\":276} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"tsvetomir.banovski@gmail.com\"} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613807,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613807} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613807,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613807,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4484,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"503e9564-ad58-44d0-9757-576b830ee22a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613806,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613806,\"participants\":[{\"id\":1001688,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001689,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613806,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":253} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613806,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613806} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613806,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613806,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"c7deb69c-6c07-4701-a67e-aac8a6e7eae5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613805,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613805,\"participants\":[{\"id\":1001686,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1001687,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613805,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613805,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613805} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613805,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613805,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"0d5af06d-774a-423e-8566-cb9f43e49711\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613698,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613698,\"participants\":[{\"id\":1001667,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001668,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613698,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613698,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613698} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613698,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613698,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"80021afa-cf61-496e-89ce-8c3e54208849\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613697,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613697,\"participants\":[{\"id\":1001665,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001666,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613697,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613697,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613697} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613697,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613697,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"26cb04a3-9455-48ca-bbec-d8afcaf66d89\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613696,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613696,\"participants\":[{\"id\":1001663,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001664,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613696,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613696,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613696} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613696,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613696,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"1394ff3a-8967-4099-957d-78dd3bd1ad06\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613695,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613695,\"participants\":[{\"id\":1001661,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001662,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613695,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613695,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613695} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613695,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613695,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8e71d37f-8fcc-4294-a951-7e7e1fa36414\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613694,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613694,\"participants\":[{\"id\":1001659,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1001660,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613694,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613694,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613694} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613694,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613694,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"e3d5ac8c-21da-4854-8976-7e5916c19626\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613157,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613157,\"participants\":[{\"id\":1000746,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000747,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613157,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613157,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613157} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613157,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613157,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"5ac0504a-ec31-4cd3-bee9-a22a17043d87\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613156,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613156,\"participants\":[{\"id\":1000744,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000745,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613156,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613156,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613156} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613156,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613156,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"dc55bf51-23a4-467e-a0eb-e005ac332df8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613155,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613155,\"participants\":[{\"id\":1000742,\"user_id\":253,\"contact_id\":null,\"lead_id\":null},{\"id\":1000743,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613155,\"team_id\":2,\"email\":\"preslava.ivanova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613155,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613155} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613155,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613155,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"3eef285e-0d37-4ed8-b4ab-aa92cf893970\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":613130,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":613130,\"participants\":[{\"id\":1000693,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000694,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":613130,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":613130,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":613130} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":613130,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":613130,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"3c8a085d-bdf1-40eb-a97e-a240a0d42001\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612924,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612924,\"participants\":[{\"id\":1000290,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000291,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612924,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":19} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":165} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612924,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612924} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612924,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612924,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"d931b6c6-ab61-4e56-863b-aed2be3cf628\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612923,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612923,\"participants\":[{\"id\":1000288,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000289,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612923,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612923,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612923} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612923,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612923,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"247ebe62-b545-410c-9a1a-a64a2a16f74f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612922,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89}} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612922,\"participants\":[{\"id\":1000286,\"user_id\":19,\"contact_id\":null,\"lead_id\":null},{\"id\":1000287,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612922,\"team_id\":2,\"email\":\"james.graham@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612922,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612922} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612922,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612922,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":165,\"stage_id\":89} {\"correlation_id\":\"8eec93ee-21ff-4839-8d92-4c5e73e5cb02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"e1add09a-4136-4471-aaab-635ce3913944\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612822,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612822,\"participants\":[{\"id\":1000080,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000081,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612822,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612822,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612822} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612822,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612822,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"0dc18256-a5c4-4809-8f4f-ae8acfa1c62a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc4dcdd9-0121-448e-8b4e-fc0e39d20a72\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612673,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612673,\"participants\":[{\"id\":999993,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999994,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612673,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612673,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612673} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612673,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612673,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"8b734f7b-ff76-4bcd-b217-f33580cc5d42\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612642,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612642,\"participants\":[{\"id\":999935,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999936,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612642,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612642,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612642} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612642,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612642,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"ba79ca47-b56d-4686-9d40-25f98db53e2d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612598,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612598,\"participants\":[{\"id\":999857,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999858,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612598,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612598,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612598} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612598,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612598,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"eee09476-7cfd-47f1-9265-8d0f1f77edc7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612597,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612597,\"participants\":[{\"id\":999855,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999856,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612597,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612597,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612597} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612597,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612597,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"62c5275c-1274-41ee-bc3f-5bbf783b9e37\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612596,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612596,\"participants\":[{\"id\":999853,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999854,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612596,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612596,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612596} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612596,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612596,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"c07694f1-899f-4ac8-be40-e00a204aac88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612595,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612595,\"participants\":[{\"id\":999851,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999852,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612595,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612595,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612595} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612595,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612595,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a42bd4c7-5a99-40a1-8f2d-310dc2de3d2e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612594,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612594,\"participants\":[{\"id\":999849,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999850,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612594,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612594,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612594} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612594,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612594,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"bb1f8c52-2f4c-4c3b-b77f-4f1a1bb3109d\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612593,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612593,\"participants\":[{\"id\":999847,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999848,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612593,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612593,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612593} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612593,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612593,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"4d5f5c05-bcfd-478f-aa51-3301a9db49f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612592,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612592,\"participants\":[{\"id\":999845,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999846,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612592,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612592,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612592} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612592,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612592,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"a80a8412-d94f-42a6-b884-72c206ac1da4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4a8732a4-99b7-41d1-b7b2-eca5b5e48e29\",\"trace_id\":\"61c44eed-65c5-4e52-a175-3bee690af53c\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612591,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612591,\"participants\":[{\"id\":999843,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999844,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612591,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612591,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612591} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612591,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612591,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"227671e6-a371-4f4c-b68e-79cfc8a40b80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612590,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612590,\"participants\":[{\"id\":999841,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999842,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612590,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612590,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612590} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612590,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612590,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"b0316038-52d2-4649-bbfd-3398e4ba616c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612589,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612589,\"participants\":[{\"id\":999839,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999840,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612589,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612589,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612589} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612589,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612589,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8d0009ec-aa6b-43eb-b5e9-9fdebab1bc88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612588,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612588,\"participants\":[{\"id\":999837,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999838,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612588,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612588,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612588} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612588,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612588,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"3759f33f-9281-45e5-82c7-b8232490ee14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612587,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612587,\"participants\":[{\"id\":999835,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999836,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612587,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612587,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612587} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612587,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612587,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e1fd0d0c-ddd7-483c-a454-704b27f83a35\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612586,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612586,\"participants\":[{\"id\":999833,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999834,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612586,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612586,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612586} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612586,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612586,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"65015bee-210a-4abd-ae8e-9b347db68ce5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612585,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612585,\"participants\":[{\"id\":999831,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999832,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612585,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612585,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612585} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612585,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612585,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"03c44248-e58c-4287-8e6d-5c619c6fb75f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612584,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612584,\"participants\":[{\"id\":999829,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999830,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612584,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612584,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612584} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612584,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612584,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"23ed7387-c743-4302-9b44-8d9813be4fe5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612583,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612583,\"participants\":[{\"id\":999827,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999828,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612583,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612583,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612583} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612583,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612583,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"aeabaf4b-f18e-43fd-aefc-396f54ca6ec9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612582,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612582,\"participants\":[{\"id\":999825,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999826,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612582,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612582,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612582} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612582,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612582,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"522ee9f2-8c92-480b-acda-f4759553f0b0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612581,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612581,\"participants\":[{\"id\":999823,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999824,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612581,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612581,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612581} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612581,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612581,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"8b4434a0-8bca-4ffb-9883-31415fdcd948\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612565,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612565,\"participants\":[{\"id\":999789,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999790,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null}]} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612565,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612565,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612565} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612565,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612565,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"ff0483e4-50c5-4943-9ac0-1521c68a84a6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612563,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612563,\"participants\":[{\"id\":999784,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999785,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612563,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":206} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612563,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612563} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612563,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:09] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612563,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"37c561fb-7972-4263-aac8-89d830ebc5c7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"b3bfac4d-fb8a-4113-a07a-e949910a9e3f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:10] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:11] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"093de884-5d00-46dd-8202-1f6294142ac4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:12] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"55d42510-0a7f-49da-92bb-3d7d04f519e0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612559,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612559,\"participants\":[{\"id\":999776,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999777,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612559,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":69,\"contact_id\":97,\"owner_id\":206} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":69,\"contact_id\":97} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":69,\"contact_id\":97,\"opportunity_id\":5011} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612559,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612559} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612559,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:13] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612559,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"771b143d-9ff2-4447-952a-0f3e56249c53\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612558,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612558,\"participants\":[{\"id\":999774,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999775,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612558,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612558,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612558} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612558,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:14] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612558,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"87d35b30-46fd-4cbe-815e-3c7fc0873c55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612557,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612557,\"participants\":[{\"id\":999772,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999773,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612557,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612557,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612557} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612557,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:16] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612557,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"f4441c9e-1575-406a-9087-739d00f7051a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612556,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612556,\"participants\":[{\"id\":999770,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999771,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612556,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612556,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612556} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612556,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612556,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"0c63e1d6-a318-43c2-8cc4-a2e00c5260e3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:17] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612555,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612555,\"participants\":[{\"id\":999768,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999769,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612555,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612555,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612555} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612555,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612555,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"3268196e-0a93-4fd3-a61b-5dfcc3e560a8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":11.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612554,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612554,\"participants\":[{\"id\":999766,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999767,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612554,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612554,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612554} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612554,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612554,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"09a1bea2-5b92-4a89-8617-bc5809db48d1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612553,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612553,\"participants\":[{\"id\":999764,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999765,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:19] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612553,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612553,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612553} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612553,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612553,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"40b197d4-a099-4e5a-9b85-7d5e01a97d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612552,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612552,\"participants\":[{\"id\":999762,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999763,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612552,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612552,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612552} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612552,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612552,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"6548c611-b94a-40c9-8a0e-d3c24ba47072\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612551,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612551,\"participants\":[{\"id\":999760,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999761,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612551,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612551,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612551} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612551,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612551,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"4cce51ee-846b-43b2-a0cd-d83dc5eff920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612550,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612550,\"participants\":[{\"id\":999758,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999759,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612550,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612550,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612550} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612550,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612550,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"b0e6efce-5447-4d7d-be32-a4dfafa64fdc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612549,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34}} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612549,\"participants\":[{\"id\":999756,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999757,\"user_id\":null,\"contact_id\":97,\"lead_id\":null}]} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612549,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinsoncrusoe@test.com\"} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612549,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612549} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612549,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612549,\"remote_search\":true,\"lead_id\":null,\"contact_id\":97,\"account_id\":69,\"opportunity_id\":5011,\"stage_id\":34} {\"correlation_id\":\"e8c5b540-3796-4bed-b52c-3f7a6b7586aa\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612365,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612365,\"participants\":[{\"id\":999563,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999564,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612365,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612365,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612365} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612365,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612365,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"e5125373-9a81-49ac-ab11-5aebfe6aea74\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-9 (truncated...)\n\"} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:22] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"611796ed-b766-420d-a544-4fdb1123b4f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"f69192c9-9ba8-48e0-b614-996bf3dcc7d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:23] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"6522d428-c400-448c-9130-a06133b21471\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"0588c797-4ae0-4d7b-b3ee-9706e7ef39df\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612183,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612183,\"participants\":[{\"id\":999227,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999228,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612183,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612183,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612183} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:24] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612183,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612183,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"946c4e96-6983-445b-a842-b212439024fd\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612182,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612182,\"participants\":[{\"id\":999225,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999226,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612182,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612182,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612182} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612182,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612182,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f5eaabe1-ed2b-4779-8907-9a7cb181c90e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.26,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612181,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612181,\"participants\":[{\"id\":999223,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999224,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"86d5bdfe-cc94-41f2-94ba-422242e4e1f5\",\"trace_id\":\"659a90d1-e357-4e8c-a391-979e687c5ae4\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612181,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612181,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612181} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612181,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612181,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"d2216c54-0324-4668-a561-66c972bd24b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612180,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612180,\"participants\":[{\"id\":999221,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":999222,\"user_id\":261,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612180,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612180,\"participants_processed\":2,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612180} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612180,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612180,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"f8c127c2-60ef-47b1-b0e2-5adb2b6d7349\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:25] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"0869934c-f4d0-46a1-8387-f2393c5bce93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:26] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"4e3d1181-634e-4ea2-8ac6-7da2a722c455\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"bd88fcdb-25fc-4e20-bec3-36897d7c6d4e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"c1d5bb08-3fac-4938-926a-3e672915d6c3\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"c1161db6-2192-487f-94d9-fb763ee00ea9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:27] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"bd974d1f-98c3-43ec-a0ee-c373b13e5a55\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:28] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"6b6b45e9-7387-4b73-a6c1-1302a6e959cc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"3d3fbb4c-6268-4e40-bf22-931be4baeb1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"75bdd542-1e62-4704-861a-810a631074bf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:29] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"923e5701-fa97-4252-a235-5cfe1a50c951\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:30] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"afecdc02-a4b8-431a-baee-e5f104160539\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"30a67f60-f844-4758-bc2c-79a6b1ec958a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"2989f086-0b73-4b12-b24c-8665376dcf18\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.9,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:31] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"0c19e519-0adf-4903-a45d-44559f23151f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"fc1002b7-ac5b-4080-b6fa-497070177a88\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"738402b4-5306-4346-9286-7b1fb94db69f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:32] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-c (truncated...)\n\"} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"2356bf77-077c-400e-ac58-cebd0719ff80\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"2e2173eb-7d9e-43e9-b8e2-2c6bb1d4c684\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"63a0af1c-277e-446c-9a48-9757a8d34ddc\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"b324376c-1fd3-497f-b0fb-004f86f50635\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b2b3cc5b-60ce-4c18-bb68-76d30013357c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:33] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"d6026499-3681-474a-85f7-3faee13605b8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"17b3d9a6-2eb0-49d1-8a00-c67c644885e1\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":1,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"112a2c70-a5f2-4500-9726-7f560d683236\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610400,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34}} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610400,\"participants\":[{\"id\":996275,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null},{\"id\":996276,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":996277,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610400,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":1460} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":244,\"contact_id\":4487} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":350} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610400,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610400} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610400,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610400,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":350,\"stage_id\":34} {\"correlation_id\":\"8cbe2d45-c42f-42bb-85b7-0d645c9e64b6\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6868b438-d843-4331-9862-f802e4cc4ff2\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f600c314-da4f-48ea-885b-f3b0db553881\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring start {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.NOTICE: Monitoring end {\"correlation_id\":\"2a3353ba-9883-42be-b596-9e38bd5fc160\",\"trace_id\":\"fc84fbbd-f6ab-40f6-8fdc-f023fbe3b46e\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ac88094e-4a12-4e5c-87dd-c7701d7a8719\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"5b7869a5-e05c-417f-819f-12774e20bb56\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72bb1bed-9270-436f-977c-a73c970415a3\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ef02c9ff-d0fc-47cb-aeb0-e8ba837de699\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e1608ca2-4101-4e24-8c9f-29ba81ce925f\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"40f1c570-c73a-4bea-99d1-0b405485c1eb\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6f43c701-78e8-4a90-bc73-feecc83e035c\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"714584dc-ec4b-479a-aecd-db6c109f4a6d\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:34] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f7f53665-81f1-4b01-86eb-56ad96f088db\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7356be9b-68c6-4c39-9fbe-d16bafce4614\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:35] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb97cad3-6d10-4315-a771-a5c3a8aeeb31\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b6a9ae37-beff-496a-820a-bcf0512308f2\",\"trace_id\":\"be38fb3e-0cfa-4c02-a66a-cc0cf8d3d54a\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.49,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73d4c333-df67-43c5-a413-4c675a3ebc5e\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0c0e087e-66cf-4404-b647-530f77b3e652\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:37] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8ae56005-eaea-4862-83a4-4c28e0deb862\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"72f691bf-4dd5-46e4-b0aa-e6d9947e244c\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:38] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9c039918-1cd4-4208-bd24-8e42d3efb19e\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"07a987cd-1db5-4796-b217-d8d2d1b6913e\",\"trace_id\":\"90eeb583-f4ef-4d3f-bf6e-2425312728c5\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:39] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"207e2c1f-73c1-428d-80a6-3c87aa383443\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3b238a85-6f7e-44ab-8dac-2e8f132b32fe\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:40] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"233b41da-91f2-45fb-8a21-80d2cd24570d\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e17eab55-f6ef-40c4-bcf7-0b2b4af23908\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:41] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"f6431de6-0cbf-4083-96fc-d316ebac17ec\",\"trace_id\":\"fab32d53-3e12-42b6-b809-50dcad19899b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"ae1e1745-b1f8-4fa9-9d96-b0ec9934cbbd\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f131d63b-7da9-4a0c-b9d5-4a2d2ae772f1\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":15} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"93d7f7d1-3a5c-47ce-bc42-1af98a032e7b\"}\n[2026-05-11 10:17:42] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168a-e (truncated...)\n\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"efb63783-8dfd-4c44-805a-c36bcb5e317e\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"34f22bc6-50a7-4f6e-96be-552d05a23255\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:43] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"624ce203-96d1-4009-ae4e-5b6635eff4b0\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":13} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"99d1cf07-a91d-4a90-8059-1fe54fb6097a\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"71db6557-d1a4-488a-bcaa-cefeb41f9f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"c4fcf2aa-0846-4e80-b18b-251b2d368949\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:44] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"286a6558-1e66-4ffb-b32f-9f823a296d14\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"c0afdc10-8cad-4dab-9147-5495fc19b7c4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1b88706b-8ac4-431d-8696-8f8766ecae33\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"d8ceac67-8853-4fbf-b4de-796abc2eadc8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"b4c629ce-833d-484c-8155-4df866fe54cf\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"168d2aac-7bb8-4249-b62a-e088ef05a5c3\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"067b89fc-5453-49ae-a3fa-5dfdb487c294\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":10} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e2d3538d-9a14-45c4-b068-84b3732061df\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:45] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"e7285c6c-728d-4284-b885-7e9e9df72706\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:46] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"5463b5ad-2286-4568-8f68-76b82d8a4c54\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"ca6930a0-aebc-4338-856e-6a439a838639\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7721c535-7311-417a-b30a-1286a84e037b\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"e20af459-b149-4a19-8ef6-4444b4cee8f9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":14} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90f3fc25-e34d-4c3a-b35c-84317a633c78\"}\n[2026-05-11 10:17:47] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.21,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":12} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6264c9dd-ba42-4c8f-a21f-3dffeb0c31c6\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"64b7efd5-f92f-42b8-95ba-9a9e76fbb676\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"aa8720ba-c5e3-4d7e-a7c3-697da34a195e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"1abedcde-ca97-4113-b4a6-60a45a16f9d8\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:48] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"d4390ffe-1359-41f6-9feb-f0bfbfdafc61\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"42a128d7-d841-4c03-a6c0-7b9fa918ec1e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"68eaf196-29ca-48a3-8e46-5bf37620dd08\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":2,\"retry_after\":10,\"delay\":11} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f997c306-a176-4f3a-8699-d9cd083d6993\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:49] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"18efa24c-257e-4842-af7d-5ec20872ab02\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"af4fe4e8-53c1-4339-8100-49dadac0f280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"68a001e2-a116-4b5d-b8e7-902d08ada842\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:51] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"19bb8a09-8a89-4524-bfc1-e972923a1f2b\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"dd53be6e-a456-46da-ab7c-c2988301922f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:52] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4d0438c5-9dc4-4b93-b643-6417ac75f31a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":1.19,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {\"exception_class\":\"SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.WARNING: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"policy\":null,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e168b-1 (truncated...)\n\"} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5b1bde17-34b2-4c96-a240-52c83ddc5c93\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"88d5107a-d1a9-4def-8f1f-6ff8bea40516\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:53] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"9eb70001-f31f-427d-9ecb-d42969509f8e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"b291b19d-e631-4390-a8ce-49431d5f566f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4b8fb89e-a1a0-4894-81d9-5d1e86570512\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"f27f33ba-8caa-49a5-9cad-cd8293e9a7db\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"af6121c1-ef51-49a6-acda-bb121812831a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:55] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"7c89eb2a-2a39-463f-abad-6b13e5fed935\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:56] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":12} {\"correlation_id\":\"9c37e4f5-1e21-4f96-86d0-2d8f2ce76d49\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":11} {\"correlation_id\":\"5a0ad4cc-8cdd-4f1e-8bae-a70a2f7b7280\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:57] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"9884d6bc-6966-4c2b-b123-bd6bff97b920\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"a7f9bc7e-977e-4032-820f-1e0b80c6214f\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":14} {\"correlation_id\":\"4674593f-9f44-4f03-8474-ff0a7926a543\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"9c459c55-c8be-453e-9540-0477f5134f6f\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"52ae8415-fd35-4109-8db4-45893cf37c4c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"3693e67e-875d-4232-a495-1621a90bf41a\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:58] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"56a279f5-3276-4781-9691-6ac712992a03\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"2149fff4-fc50-4b5e-8346-f4fe92446383\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.31,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:17:59] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":13} {\"correlation_id\":\"6c488719-2433-44c2-be14-6234030389cb\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"af37fbba-e927-4df9-840b-3ede48a1d911\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"534825cf-e6d0-42f8-8ff6-18fee9ebbcf9\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:00] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":15} {\"correlation_id\":\"13c3f8a7-53c0-490e-915d-f30216c6fae9\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"785d023d-231c-4c69-9e14-64b9f386cd8a\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"aea37783-669f-433b-aac7-ead252f60285\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"73386989-234b-4074-93cd-b907d73fb039\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"67837137-7da9-4fc3-807c-fa87dbcc5090\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1d0c22f1-5e71-452c-94ab-4a7ba39ee8be\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:01] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {\"job_class\":\"Jiminny\\\\Jobs\\\\Crm\\\\MatchActivityCrmData\",\"attempts\":3,\"retry_after\":10,\"delay\":10} {\"correlation_id\":\"5e4163ac-fdc7-49df-89de-383bf3f5bcd4\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:02] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9476099f-6f93-4402-b763-b075c4f8ed44\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7e0e12d1-b270-490b-848b-763e373c90e0\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"adaf1f1e-8477-469f-86c9-9c59d2623f11\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:03] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"1235043b-578e-49e0-9ebe-230be6d9a8f8\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610539,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610539,\"participants\":[{\"id\":996485,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996486,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:04] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.47,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:04] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.3,\"average_seconds_per_request\":0.3} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:05] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1042ef38-481f-4e55-9261-bb89ceb4cd6f\",\"trace_id\":\"3cbbfc20-36d7-4827-9e77-e5ea12d34c82\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610539,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610539,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610539} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610539,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610539,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"556047b1-b970-491f-90a1-03a361d35100\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610878,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610878,\"participants\":[{\"id\":997035,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997036,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:06] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610878,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610878,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610878} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610878,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610878,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"657e3baa-5806-4803-8f06-5375e09f4728\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612340,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612340,\"participants\":[{\"id\":999516,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999517,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999518,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999519,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612340,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.25,\"average_seconds_per_request\":0.25} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.48,\"average_seconds_per_request\":0.48} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612340,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612340} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612340,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:07] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612340,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6b8427b4-3b81-40ed-b97f-336493ac466a\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612360,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612360,\"participants\":[{\"id\":999552,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999553,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999565,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612360,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612360,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612360} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612360,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612360,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bea3a6fc-5389-4a59-a601-2f8fe9a2d01c\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612339,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612339,\"participants\":[{\"id\":999514,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999515,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999540,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612339,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612339,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612339} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612339,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612339,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"f92f5ee2-fe1d-48c0-812c-1ef5822e650b\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611455,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611455,\"participants\":[{\"id\":997961,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997962,\"user_id\":1460,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"support@staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/support%40staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:08] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.66,\"average_seconds_per_request\":0.66} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e0173b67-adc7-4861-acea-33ec563fa8bc\",\"trace_id\":\"df5cbecf-dde1-4674-82c8-8b7a2f4b74de\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:09] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.3,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:09] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.26,\"average_seconds_per_request\":0.26} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611455,\"team_id\":2,\"email\":\"aneliya.angelova@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611455,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611455} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611455,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611455,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"dd54f05a-e554-44ab-9379-da61bcac65a5\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610915,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610915,\"participants\":[{\"id\":997104,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997105,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610915,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610915,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610915} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610915,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610915,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"b8548036-8907-428c-a1a8-534820e4d593\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610528,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610528,\"participants\":[{\"id\":996463,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996464,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610528,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610528,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610528} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610528,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610528,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"538a5f7a-a2da-4a62-8b62-211aeb5dc208\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611087,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611087,\"participants\":[{\"id\":997368,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997369,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611087,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611087,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611087} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611087,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611087,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"356103b6-5095-43de-8a30-6e30a04734da\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611076,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611076,\"participants\":[{\"id\":997346,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997347,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611076,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611076,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611076} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611076,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611076,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"9e9f9d73-ae12-4bdb-86a9-b2dfc5eadb1e\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610497,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610497,\"participants\":[{\"id\":996401,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996402,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610497,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610497,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610497} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610497,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610497,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57a562f3-a27e-4b76-9ef2-191fc918812c\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610867,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610867,\"participants\":[{\"id\":997011,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997012,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610867,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610867,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610867} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610867,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610867,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"6d84e7da-d52b-4ded-b8d7-965a68fa0f14\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610490,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610490,\"participants\":[{\"id\":996385,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996386,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610490,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610490,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610490} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610490,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610490,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cf6a7852-6696-4be0-b6ae-0d2ba5896580\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610506,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610506,\"participants\":[{\"id\":996419,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996420,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610506,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610506,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610506} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610506,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610506,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8496279e-9085-40b8-9c1f-8b7b0844ca74\"}\n[2026-05-11 10:18:10] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610885,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:10] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610885,\"participants\":[{\"id\":997051,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997052,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610885,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610885,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610885} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610885,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610885,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"bb9bd43b-dc0f-49a3-9926-6e7b545e4484\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610874,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610874,\"participants\":[{\"id\":997025,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997026,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610874,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610874,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610874} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610874,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610874,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"57100b89-c0f3-48a5-aafb-af04e1e7b2a8\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610617,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610617,\"participants\":[{\"id\":996641,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996642,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610617,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610617,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610617} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610617,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610617,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"660593a5-69f3-4b40-a2c6-ca235b404df4\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614382,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614382,\"participants\":[{\"id\":1002632,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002633,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"nikolay.nikolov@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring start {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:11] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:11] local.NOTICE: Monitoring end {\"correlation_id\":\"f1c8fc03-337f-4edb-a859-cd9fb18b900e\",\"trace_id\":\"503eff58-a255-4b63-9001-481d9a9bd530\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:12] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.42,\"average_seconds_per_request\":0.42} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614382,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614382,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614382} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:14] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614382,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614382,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"cfa58e4a-596f-4cd7-923f-89852d3dd448\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614381,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614381,\"participants\":[{\"id\":1002630,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002631,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614381,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614381,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614381} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614381,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614381,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"68a943a9-28db-4452-81a3-9bb8e3bbd404\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.55,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610426,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610426,\"participants\":[{\"id\":996306,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996307,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610426,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610426,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610426} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610426,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:15] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610426,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"90da6de9-ad64-4ba1-8913-870cd9008e44\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612560,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612560,\"participants\":[{\"id\":999778,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999779,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447782589921@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447782589921%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.27,\"average_seconds_per_request\":0.27} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:16] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4f01fa5e-5837-4b03-af04-ccad937f80f4\",\"trace_id\":\"7ea236cf-a366-4cea-8e77-3417ec22eac5\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612560,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612560,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612560} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612560,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612560,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"768d721d-1a47-4144-bc8b-43d4aad7cf7a\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610462,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610462,\"participants\":[{\"id\":996353,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996354,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610462,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610462,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610462} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610462,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610462,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"d20720d8-78ec-4300-9c6c-6e6d63dd5979\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612819,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612819,\"participants\":[{\"id\":1000073,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null},{\"id\":1000074,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000075,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":244,\"contact_id\":4487,\"owner_id\":261} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":244,\"contact_id\":4487,\"opportunity_id\":299} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612819,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"adelina.petrova@jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/adelina.petrova%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/contact/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.24,\"average_seconds_per_request\":0.24} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\",\"crm\":\"hubspot\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:18] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"domain\",\"identifier\":\"jiminny.com\"} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"749766179\",\"config_id\":2} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [HubSpot] CRM Search requested {\"request\":{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"associations.company\",\"operator\":\"EQ\",\"value\":\"749766179\"},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedwon\",\"4040964\",\"59247967\"]},{\"propertyName\":\"dealstage\",\"operator\":\"NOT_IN\",\"values\":[\"closedlost\",\"4040965\",\"59247968\"]}]}],\"sorts\":[{\"propertyName\":\"modifieddate\",\"direction\":\"DESCENDING\"}],\"properties\":[\"dealname\",\"amount\",\"hubspot_owner_id\",\"pipeline\",\"dealstage\",\"closedate\",\"deal_currency_code\"],\"limit\":200}} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":10,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"add7477b-8e9d-44ef-9c16-cf763d7fd973\",\"trace_id\":\"0a4036d4-4c6b-4724-8efb-d8375a7dfe6a\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612819,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612819} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612819,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612819,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"4935e6a6-a430-454c-abfd-3ecbfe2a8093\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612847,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36}} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612847,\"participants\":[{\"id\":1000130,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1000131,\"user_id\":261,\"contact_id\":null,\"lead_id\":null},{\"id\":1000151,\"user_id\":null,\"contact_id\":4487,\"lead_id\":null}]} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"adelina.petrova@jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"adelina.petrova@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612847,\"team_id\":2,\"email\":\"adelina.petrova@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"robinson@crusoe.com\"} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612847,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612847} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612847,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612847,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4487,\"account_id\":244,\"opportunity_id\":299,\"stage_id\":36} {\"correlation_id\":\"59a52e35-0442-4b9c-ba94-13987f6e5045\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610451,\"participants\":[{\"id\":996340,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996341,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610451} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"8852008d-42e1-4838-bf44-0fb139bad2c7\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612562,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612562,\"participants\":[{\"id\":999782,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999783,\"user_id\":206,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"447782589921@txt.staging.jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447782589921@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612562,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612562,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612562} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612562,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612562,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"c88f4636-6a5a-42b8-8b5f-57817eb88000\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610764,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610764,\"participants\":[{\"id\":996951,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996952,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610764,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610764,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610764} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610764,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610764,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"de0766e3-67e9-4a70-ade6-579313484aab\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614436,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614436,\"participants\":[{\"id\":1002751,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002752,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614436,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614436,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614436} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614436,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614436,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"26844961-f2c1-4818-8fbf-4e75fed45dd0\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610438,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610438,\"participants\":[{\"id\":996320,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996321,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610438,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610438,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610438} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610438,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610438,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"7d7ce093-516d-49a9-aa85-d06a603548de\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":615092,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":615092,\"participants\":[{\"id\":1004102,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1004103,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":615092,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":615092,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":615092} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":615092,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":615092,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"701da656-d862-4f53-a173-98bd0462ba59\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.23,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610403,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610403,\"participants\":[{\"id\":996282,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996283,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610403,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610403,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610403} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610403,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610403,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"cb6cee8f-e823-491f-a523-22966ea386a9\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610935,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610935,\"participants\":[{\"id\":997141,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997142,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610935,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610935,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610935} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610935,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610935,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"2882970b-de3a-4bff-8cc2-c9d0182ad10c\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610470,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610470,\"participants\":[{\"id\":996369,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":996370,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610470,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610470,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610470} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610470,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610470,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\",\"correlation_id\":\"0d9cdf36-1d5a-4bbb-8f3e-5b28e82a73b2\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":610900,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":610900,\"participants\":[{\"id\":997081,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997082,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":610900,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":610900,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":610900} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":610900,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":610900,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"64a23169-398d-4b52-b6ff-2027ac5ca8f5\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":614378,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null}} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":614378,\"participants\":[{\"id\":1002623,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":1002624,\"user_id\":null,\"contact_id\":6167,\"lead_id\":null},{\"id\":1002625,\"user_id\":89,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:20] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"nikolay.nikolov@jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"nikolay.nikolov@jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"nmalchev@gmail.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":614378,\"team_id\":2,\"email\":\"nikolay.nikolov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":614378,\"participants_processed\":3,\"exact_matches\":1,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":614378} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":614378,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":614378,\"remote_search\":true,\"lead_id\":null,\"contact_id\":6167,\"account_id\":null,\"opportunity_id\":null,\"stage_id\":null} {\"correlation_id\":\"4770fe06-51ae-468a-b56b-ba82eab8d88e\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612561,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612561,\"participants\":[{\"id\":999780,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999781,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612561,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache miss, calling the API {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Hubspot] Failed to fetch contact {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"reason\":\"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/447700174614.447782589921.OeREojLVnk%40txt.staging.jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {\"identifier_type\":\"email\",\"identifier\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"447700174614.447782589921.OeREojLVnk@txt.staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612561,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612561} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612561,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612561,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"4aabf216-0b76-4e76-968f-76cae4d9d3e7\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":612336,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36}} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":612336,\"participants\":[{\"id\":999508,\"user_id\":null,\"contact_id\":4491,\"lead_id\":null},{\"id\":999509,\"user_id\":206,\"contact_id\":null,\"lead_id\":null},{\"id\":999512,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":999513,\"user_id\":null,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Searching DB for opportunity by owner {\"account_id\":243,\"contact_id\":4491,\"owner_id\":206} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Fallback DB opportunity search {\"account_id\":243,\"contact_id\":4491} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: ProspectCache - Opportunity DB search results {\"account_id\":243,\"contact_id\":4491,\"opportunity_id\":276} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"horencho@gmail.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":612336,\"team_id\":2,\"email\":\"horen.kirazyan@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":612336,\"participants_processed\":4,\"exact_matches\":1,\"domain_matches\":0,\"best_match_found\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":612336} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":612336,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":612336,\"remote_search\":true,\"lead_id\":null,\"contact_id\":4491,\"account_id\":243,\"opportunity_id\":276,\"stage_id\":36} {\"correlation_id\":\"9fbdbe9b-2bfb-4f6b-b8cd-2459c7919210\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Starting CRM data matching {\"activity\":611451,\"remote_search\":true,\"set_configuration\":2,\"old_state\":{\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89}} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Participants old state {\"activity\":611451,\"participants\":[{\"id\":997955,\"user_id\":null,\"contact_id\":null,\"lead_id\":null},{\"id\":997956,\"user_id\":18,\"contact_id\":null,\"lead_id\":null}]} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Cache / local search hit {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {\"identifier_type\":\"email\",\"identifier\":\"support@staging.jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [Prospect match] Resolved company domain from email {\"email\":\"support@staging.jiminny.com\",\"domain\":\"jiminny.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {\"activity_id\":611451,\"team_id\":2,\"email\":\"veselin.kulov@jiminny.onmicrosoft.com\"} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [CrmActivityService] CRM matching completed {\"activity_id\":611451,\"participants_processed\":2,\"exact_matches\":0,\"domain_matches\":1,\"best_match_found\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ EsUpdateTarget ] Update single target {\"target\":\"activities\",\"purpose\":\"searchable-observer-update\",\"entityId\":611451} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {\"entityType\":\"activities\",\"entityId\":611451,\"collectionKey\":\"activities-for-update-priority\",\"withPriority\":true} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {\"activity\":611451,\"remote_search\":true,\"lead_id\":null,\"contact_id\":null,\"account_id\":26,\"opportunity_id\":22,\"stage_id\":89} {\"correlation_id\":\"08b7fc4c-2330-4317-a9bd-e4b8a5164358\",\"trace_id\":\"8e45b868-2eb5-42f8-a91e-22951e49d57d\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:16:00, 2026-05-11 10:18:00] {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5cd332f8-5b05-4813-bf28-dc3f5c776c31\",\"trace_id\":\"9d576391-5ec6-47d4-9c55-77e4dc0e5881\"}\n[2026-05-11 10:18:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5d165f52-8b9b-49f4-826c-5e6effb36469\",\"trace_id\":\"8d23eb87-94aa-45be-a25c-60adf651f65b\"}\n[2026-05-11 10:18:26] local.INFO: [ EsUpdateProcessManager ] Finished updating entities in ES {\"worker\":\"\",\"peak_memory\":\"99.73 MB\",\"elapsed_seconds\":0.38,\"update_target\":\"activities\",\"should_iterate_again\":false} {\"correlation_id\":\"4ad05333-9afb-492e-9f0f-b2909ac45b32\",\"trace_id\":\"3d8feb24-b173-4158-b0a4-4cf33af85066\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b818863b-2a43-41d9-8ff6-fee7c3d716bc\",\"trace_id\":\"247ba4af-b613-440c-94fe-1c5b9acb9a49\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ebc86a92-142f-437d-993d-b5babcf2cc26\",\"trace_id\":\"afbbde14-96ad-42a5-a9b8-acbb3e1d637a\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring start {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:08] local.NOTICE: Monitoring end {\"correlation_id\":\"e77a8f39-a88c-4046-abe4-817093d395f4\",\"trace_id\":\"17ae50a2-26b7-48ab-a9a4-1188e484d567\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"82c9f998-b4ec-42a5-9114-b34b4ef4418e\",\"trace_id\":\"398aab71-a970-4adb-bfd2-e7003c988e9b\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:19:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"00ff8a16-df56-4dbe-89ee-949f1fec10ae\",\"trace_id\":\"48f7dab8-39b8-47ff-badc-9e61a319de61\"}\n[2026-05-11 10:20:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2fa5b0c6-7488-44c6-93cb-2c97d3dd0e22\",\"trace_id\":\"ba4e66e9-8f87-4745-8d42-1a604ad0e217\"}\n[2026-05-11 10:20:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"2fa5b0c6-7488-44c6-93cb-2c97d3dd0e22\",\"trace_id\":\"ba4e66e9-8f87-4745-8d42-1a604ad0e217\"}\n[2026-05-11 10:20:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2fa5b0c6-7488-44c6-93cb-2c97d3dd0e22\",\"trace_id\":\"ba4e66e9-8f87-4745-8d42-1a604ad0e217\"}\n[2026-05-11 10:20:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ff04c3c8-37ec-4fc2-a6b3-b821bfa798a1\",\"trace_id\":\"8a9e705c-56b1-4d8a-8768-a73d75428bdf\"}\n[2026-05-11 10:20:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ff04c3c8-37ec-4fc2-a6b3-b821bfa798a1\",\"trace_id\":\"8a9e705c-56b1-4d8a-8768-a73d75428bdf\"}\n[2026-05-11 10:20:12] local.NOTICE: Monitoring start {\"correlation_id\":\"add6d280-ba4b-4bed-b685-48f6c7138f63\",\"trace_id\":\"b73d73a4-10a3-405e-b1d8-c28149fd02e7\"}\n[2026-05-11 10:20:12] local.NOTICE: Monitoring end {\"correlation_id\":\"add6d280-ba4b-4bed-b685-48f6c7138f63\",\"trace_id\":\"b73d73a4-10a3-405e-b1d8-c28149fd02e7\"}\n[2026-05-11 10:20:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b6f27226-9ba6-476a-97c7-2f979b24192e\",\"trace_id\":\"d8265844-c686-42da-aec4-a3935c6e7846\"}\n[2026-05-11 10:20:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b6f27226-9ba6-476a-97c7-2f979b24192e\",\"trace_id\":\"d8265844-c686-42da-aec4-a3935c6e7846\"}\n[2026-05-11 10:20:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:16] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:16] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"136f8ecb-c166-4cff-b7b1-d2dbec28375a\",\"trace_id\":\"c6873c9e-763f-4514-af98-8dc617b80938\"}\n[2026-05-11 10:20:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:17] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:18:00, 2026-05-11 10:20:00] {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:17] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:18:00, 2026-05-11 10:20:00] {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"30e82931-90b9-4e5d-85c0-b02c24127fef\",\"trace_id\":\"604e7230-5a26-4c58-87fc-89f3a0998bca\"}\n[2026-05-11 10:20:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"96a418e4-766c-47b9-a1ff-954e236284b0\",\"trace_id\":\"183cebf6-abdc-43c0-9553-d92b54ed6aee\"}\n[2026-05-11 10:20:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"96a418e4-766c-47b9-a1ff-954e236284b0\",\"trace_id\":\"183cebf6-abdc-43c0-9553-d92b54ed6aee\"}\n[2026-05-11 10:20:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"72dc0355-eaa2-49c7-8505-d6878c6979cf\",\"trace_id\":\"7116edfd-f3c9-421f-8da0-c974bcc89b30\"}\n[2026-05-11 10:20:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"72dc0355-eaa2-49c7-8505-d6878c6979cf\",\"trace_id\":\"7116edfd-f3c9-421f-8da0-c974bcc89b30\"}\n[2026-05-11 10:20:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"13f58aec-c028-4abd-a682-187350d1dfeb\",\"trace_id\":\"c33a24c2-2793-4a9e-86a3-baf7fa638e43\"}\n[2026-05-11 10:20:21] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"13f58aec-c028-4abd-a682-187350d1dfeb\",\"trace_id\":\"c33a24c2-2793-4a9e-86a3-baf7fa638e43\"}\n[2026-05-11 10:20:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"13f58aec-c028-4abd-a682-187350d1dfeb\",\"trace_id\":\"c33a24c2-2793-4a9e-86a3-baf7fa638e43\"}\n[2026-05-11 10:20:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:22] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:10:00, 2026-05-11 10:15:00] {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:22] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:10:00, 2026-05-11 10:15:00] {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fe2b8e6e-e552-4ea6-9940-41269518f9a8\",\"trace_id\":\"589aa718-fba7-4197-9cdb-ffd8c37c2ba8\"}\n[2026-05-11 10:20:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:23] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:15\",\"to\":\"10:20\"} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:23] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:10\",\"to\":\"00:15\"} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"52b11778-5d6f-4c83-a20d-3adefdb779ae\",\"trace_id\":\"968ccbbe-94e1-426e-8863-049b88d608f6\"}\n[2026-05-11 10:20:25] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:25] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:25] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:26] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"8212a466-90aa-4e17-94fc-2ed0898d3d88\",\"trace_id\":\"ea16345d-488d-4f59-a458-043d14a6922a\"}\n[2026-05-11 10:20:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0abde2a5-83dc-444e-9372-f2134403833e\",\"trace_id\":\"265d74d8-d739-4506-98fa-d7528a97a6a9\"}\n[2026-05-11 10:20:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"58b4e029-5c87-4bfd-97d9-bf09f07de93d\",\"trace_id\":\"019a9c46-da79-4fb0-bbfc-a1adc73d1bc1\"}\n[2026-05-11 10:20:28] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:28] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:28] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:22:28.938115Z\"} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"58b4e029-5c87-4bfd-97d9-bf09f07de93d\",\"trace_id\":\"019a9c46-da79-4fb0-bbfc-a1adc73d1bc1\"}\n[2026-05-11 10:20:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0abde2a5-83dc-444e-9372-f2134403833e\",\"trace_id\":\"265d74d8-d739-4506-98fa-d7528a97a6a9\"}\n[2026-05-11 10:20:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"55b75dbc-a484-4333-98cd-73ddfc7ac530\",\"trace_id\":\"a35f4804-0635-4e5f-bc3e-2ca67f4a6de4\"}\n[2026-05-11 10:20:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"55b75dbc-a484-4333-98cd-73ddfc7ac530\",\"trace_id\":\"a35f4804-0635-4e5f-bc3e-2ca67f4a6de4\"}\n[2026-05-11 10:20:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"adf166f0-57f0-46a9-a389-9ff0cf327f8c\",\"trace_id\":\"022378eb-a08a-458a-a6e0-91facbd00432\"}\n[2026-05-11 10:20:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"adf166f0-57f0-46a9-a389-9ff0cf327f8c\",\"trace_id\":\"022378eb-a08a-458a-a6e0-91facbd00432\"}\n[2026-05-11 10:20:34] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:39] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:20:54] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cb3067bf-9fb7-4f4a-9bed-cd02cf91a685\",\"trace_id\":\"48a1ca4a-e7f4-4e27-9300-e9d31e949410\"}\n[2026-05-11 10:21:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"cb3067bf-9fb7-4f4a-9bed-cd02cf91a685\",\"trace_id\":\"48a1ca4a-e7f4-4e27-9300-e9d31e949410\"}\n[2026-05-11 10:21:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cb3067bf-9fb7-4f4a-9bed-cd02cf91a685\",\"trace_id\":\"48a1ca4a-e7f4-4e27-9300-e9d31e949410\"}\n[2026-05-11 10:21:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4d0f11d7-a469-47a8-8117-621c74048dfb\",\"trace_id\":\"5de7b33f-4f7f-4110-9e8f-6b436d79ade0\"}\n[2026-05-11 10:21:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4d0f11d7-a469-47a8-8117-621c74048dfb\",\"trace_id\":\"5de7b33f-4f7f-4110-9e8f-6b436d79ade0\"}\n[2026-05-11 10:21:08] local.NOTICE: Monitoring start {\"correlation_id\":\"6bdd22fb-795a-45fd-8b9f-7a828d72d3ff\",\"trace_id\":\"ee68ac31-0507-4f4c-851f-fed983af5b11\"}\n[2026-05-11 10:21:08] local.NOTICE: Monitoring end {\"correlation_id\":\"6bdd22fb-795a-45fd-8b9f-7a828d72d3ff\",\"trace_id\":\"ee68ac31-0507-4f4c-851f-fed983af5b11\"}\n[2026-05-11 10:21:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"23d6dfa8-a7c5-4e07-9560-ac2b9edca59b\",\"trace_id\":\"8daa12ab-4140-48cc-865f-8caf73c4756d\"}\n[2026-05-11 10:21:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"23d6dfa8-a7c5-4e07-9560-ac2b9edca59b\",\"trace_id\":\"8daa12ab-4140-48cc-865f-8caf73c4756d\"}\n[2026-05-11 10:21:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:11] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:11] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3f8cdb3c-956c-422c-9cc2-85926e6714c5\",\"trace_id\":\"9f9eeb1d-471d-4ce5-ae44-a95b361f3c1f\"}\n[2026-05-11 10:21:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"dca67603-c9be-467a-bfe4-2b74567cac53\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"dca67603-c9be-467a-bfe4-2b74567cac53\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24178328,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.31,\"average_seconds_per_request\":0.31} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":339.28} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":425.88,\"usage\":24265920,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"6371f495-3629-460b-be56-27e5f2378656\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24243920,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:14] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":14.69,\"usage\":24254648,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"8f54b183-7e2d-4aca-9cb0-b1968fe1a6d1\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24212152,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":6.73,\"usage\":24228272,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"0c44039f-a2cb-4619-a31d-d81bc3f36356\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24188912,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:15] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":10.24,\"usage\":24231856,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"b7004db3-c430-445f-9fcc-7feba7ccb0d8\",\"trace_id\":\"48db88db-7404-47c5-8cbd-d3b237ae1091\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":57,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":177.4,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:21:25] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"ee6a8e4e-b2ce-4906-b951-46cfa76f72f0\",\"trace_id\":\"7bf0b622-bf72-4972-9d54-6324352ee0e0\"}\n[2026-05-11 10:22:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3bf2248c-ad1e-435e-87aa-ac94afaddee2\",\"trace_id\":\"3c60287a-2ec2-4ae8-8ce7-0f2589186a27\"}\n[2026-05-11 10:22:08] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"3bf2248c-ad1e-435e-87aa-ac94afaddee2\",\"trace_id\":\"3c60287a-2ec2-4ae8-8ce7-0f2589186a27\"}\n[2026-05-11 10:22:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3bf2248c-ad1e-435e-87aa-ac94afaddee2\",\"trace_id\":\"3c60287a-2ec2-4ae8-8ce7-0f2589186a27\"}\n[2026-05-11 10:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cc7263ec-0925-4031-8df0-79534a303c7b\",\"trace_id\":\"b72980a3-0c17-453c-829a-8757cac12f35\"}\n[2026-05-11 10:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cc7263ec-0925-4031-8df0-79534a303c7b\",\"trace_id\":\"b72980a3-0c17-453c-829a-8757cac12f35\"}\n[2026-05-11 10:22:14] local.NOTICE: Monitoring start {\"correlation_id\":\"480dd732-d728-4670-9484-e9c2def7b3c1\",\"trace_id\":\"daef0ed3-e82d-4316-b8ab-b03ea2a814e1\"}\n[2026-05-11 10:22:14] local.NOTICE: Monitoring end {\"correlation_id\":\"480dd732-d728-4670-9484-e9c2def7b3c1\",\"trace_id\":\"daef0ed3-e82d-4316-b8ab-b03ea2a814e1\"}\n[2026-05-11 10:22:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"045e36da-9d9e-48c0-86f5-57240fcc0474\",\"trace_id\":\"50851e0f-b51f-46b7-8267-3b34dc31d290\"}\n[2026-05-11 10:22:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"045e36da-9d9e-48c0-86f5-57240fcc0474\",\"trace_id\":\"50851e0f-b51f-46b7-8267-3b34dc31d290\"}\n[2026-05-11 10:22:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d305f739-3d38-4085-aaf8-149bc0d9a06f\",\"trace_id\":\"1b247581-3cde-4405-9b54-6acaaf96909f\"}\n[2026-05-11 10:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:30] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:20:00, 2026-05-11 10:22:00] {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:30] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:20:00, 2026-05-11 10:22:00] {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"580d11b7-36e5-4eae-885a-e86c30e4cf27\",\"trace_id\":\"d19f8295-8f97-4d04-b322-6fc4cd335e93\"}\n[2026-05-11 10:22:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b0bad54a-de51-4132-8760-3aa430fbeaa0\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:37] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"e44d2d83-432a-40dc-82ed-bb636a1162bd\",\"trace_id\":\"e4bf8ea2-ae0d-4f2a-9d07-e146c71d065f\"}\n[2026-05-11 10:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e5a63cea-0e84-401b-92de-9b1c22e7560e\",\"trace_id\":\"be5864a6-ba9f-45e9-bf23-1059d0c7a8ba\"}\n[2026-05-11 10:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e5a63cea-0e84-401b-92de-9b1c22e7560e\",\"trace_id\":\"be5864a6-ba9f-45e9-bf23-1059d0c7a8ba\"}\n[2026-05-11 10:22:45] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2ab4f96e-cb0c-45c5-aaff-5f11c58c9643\",\"trace_id\":\"7927db97-1937-43e9-bc89-cae94ed54be7\"}\n[2026-05-11 10:22:45] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2ab4f96e-cb0c-45c5-aaff-5f11c58c9643\",\"trace_id\":\"7927db97-1937-43e9-bc89-cae94ed54be7\"}\n[2026-05-11 10:22:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"connect-and-sell\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Start user synchronisation {\"provider\":\"justcall\",\"teams_count\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Synchronising team {\"provider\":\"justcall\",\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf9285a-8ded-4a8b-bd7d-ec68c398f2f9\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1367,\"sociable_id\":1071,\"provider_user_id\":\"005O4000003s5c7IAA\",\"expires\":null,\"refresh_token_expires\":null,\"provider\":\"salesforce\",\"state\":\"full-refresh\",\"auth_scope\":\"refresh_token web api\",\"retry_after\":null,\"created_at\":\"2024-09-10 07:05:21\",\"updated_at\":\"2026-01-14 07:00:58\"}}} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":1071,\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.WARNING: Failed to sync external users {\"message\":\"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.\",\"provider\":\"justcall\",\"team_id\":1,\"team\":\"jiminny\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"ringcentral\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"avaya\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"telus\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"salesloft\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"talkdesk\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"vonage\"} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Done {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:22:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8e478d65-ba6f-4fec-908d-baafb99a3034\",\"trace_id\":\"d7b2b770-ecb5-466c-b89b-c9d9785d6dc8\"}\n[2026-05-11 10:23:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"89f4e106-bab3-436f-87ec-18fadaea9834\",\"trace_id\":\"1c6f9a74-e518-4c2f-bbe7-8f453ce1e5db\"}\n[2026-05-11 10:23:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"89f4e106-bab3-436f-87ec-18fadaea9834\",\"trace_id\":\"1c6f9a74-e518-4c2f-bbe7-8f453ce1e5db\"}\n[2026-05-11 10:23:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"89f4e106-bab3-436f-87ec-18fadaea9834\",\"trace_id\":\"1c6f9a74-e518-4c2f-bbe7-8f453ce1e5db\"}\n[2026-05-11 10:23:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"73542ef5-1dcf-49ff-a68f-f3b59f00f8f9\",\"trace_id\":\"53f0e66b-d6a2-4dce-91bc-167397bbcbb4\"}\n[2026-05-11 10:23:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"73542ef5-1dcf-49ff-a68f-f3b59f00f8f9\",\"trace_id\":\"53f0e66b-d6a2-4dce-91bc-167397bbcbb4\"}\n[2026-05-11 10:23:15] local.NOTICE: Monitoring start {\"correlation_id\":\"c42a9140-f8c8-4890-b080-9577f34b4d0b\",\"trace_id\":\"2e2d238c-88b3-467c-80cc-498f7d93d865\"}\n[2026-05-11 10:23:15] local.NOTICE: Monitoring end {\"correlation_id\":\"c42a9140-f8c8-4890-b080-9577f34b4d0b\",\"trace_id\":\"2e2d238c-88b3-467c-80cc-498f7d93d865\"}\n[2026-05-11 10:23:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3fb01e13-10f5-4cdd-b0d2-409650ba47a4\",\"trace_id\":\"e6f9ba96-932b-4bc2-bbb8-2a311b843d97\"}\n[2026-05-11 10:23:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3fb01e13-10f5-4cdd-b0d2-409650ba47a4\",\"trace_id\":\"e6f9ba96-932b-4bc2-bbb8-2a311b843d97\"}\n[2026-05-11 10:23:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:18] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:18] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d1b0cfa7-f403-4e8f-af3e-cc5f565d3a8f\",\"trace_id\":\"14c2f151-c14e-4795-af59-dca74251df51\"}\n[2026-05-11 10:23:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0334ac42-ef25-4ca6-b9d5-a54eb7340b49\",\"trace_id\":\"4e2661ff-8780-4e2a-9ce3-cb7089e29770\"}\n[2026-05-11 10:23:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0334ac42-ef25-4ca6-b9d5-a54eb7340b49\",\"trace_id\":\"4e2661ff-8780-4e2a-9ce3-cb7089e29770\"}\n[2026-05-11 10:23:31] local.INFO: [integration-app] Request {\"request\":\"GET connections\",\"full_target\":\"connections\"} {\"correlation_id\":\"06a5a57b-ba5f-4fd2-9581-1f1b88dd5218\",\"trace_id\":\"6d3d2375-2629-4141-99e1-2a2421935ebb\"}\n[2026-05-11 10:23:32] local.INFO: [integration-app] Connection state identified {\"teamId\":3143,\"connection_name\":\"Connection to 66fe6c913202f3a165e3c14d for Dev Zoho CRM client\",\"remote_connection_id\":\"69e0b983da98fa74f98aebfb\",\"is_disconnected\":false,\"is_deactivated\":false,\"is_valid\":true} {\"correlation_id\":\"06a5a57b-ba5f-4fd2-9581-1f1b88dd5218\",\"trace_id\":\"6d3d2375-2629-4141-99e1-2a2421935ebb\"}\n[2026-05-11 10:24:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8e890248-7081-459b-86e7-b0eed9ae954a\",\"trace_id\":\"c55f1643-7a81-4ac8-bb91-3a07e96c1371\"}\n[2026-05-11 10:24:07] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"8e890248-7081-459b-86e7-b0eed9ae954a\",\"trace_id\":\"c55f1643-7a81-4ac8-bb91-3a07e96c1371\"}\n[2026-05-11 10:24:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8e890248-7081-459b-86e7-b0eed9ae954a\",\"trace_id\":\"c55f1643-7a81-4ac8-bb91-3a07e96c1371\"}\n[2026-05-11 10:24:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5c387516-009d-44c8-903a-0e41edb55144\",\"trace_id\":\"909fe43e-4a48-4ce6-9e9f-612e49c4899c\"}\n[2026-05-11 10:24:10] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5c387516-009d-44c8-903a-0e41edb55144\",\"trace_id\":\"909fe43e-4a48-4ce6-9e9f-612e49c4899c\"}\n[2026-05-11 10:24:12] local.NOTICE: Monitoring start {\"correlation_id\":\"4f81d4a7-cf98-4927-8f5a-073ae73abdb7\",\"trace_id\":\"a697b539-71ff-4407-8b0d-c4430ae15074\"}\n[2026-05-11 10:24:12] local.NOTICE: Monitoring end {\"correlation_id\":\"4f81d4a7-cf98-4927-8f5a-073ae73abdb7\",\"trace_id\":\"a697b539-71ff-4407-8b0d-c4430ae15074\"}\n[2026-05-11 10:24:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e72fbc16-6e70-4c14-8820-a47ad5706362\",\"trace_id\":\"1b6d2b66-bfaa-4d8e-a3ee-9091aa32e8a8\"}\n[2026-05-11 10:24:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e72fbc16-6e70-4c14-8820-a47ad5706362\",\"trace_id\":\"1b6d2b66-bfaa-4d8e-a3ee-9091aa32e8a8\"}\n[2026-05-11 10:24:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:16] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:16] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"95a2c96b-ecd6-4c26-a305-f8ffd29c6b3b\",\"trace_id\":\"262c7198-00ea-4cc5-a221-8ea6dc26c67f\"}\n[2026-05-11 10:24:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:17] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:22:00, 2026-05-11 10:24:00] {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:17] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:22:00, 2026-05-11 10:24:00] {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d828b3d8-7862-4e3d-846c-2f1bb330c819\",\"trace_id\":\"f5c19646-70c7-442a-bd90-84a3f98e66fc\"}\n[2026-05-11 10:24:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:20] local.ERROR: [Aircall] Re-activating webhooks failed {\"team_id\":1,\"reason\":\"{\\\"message\\\":\\\"Forbidden\\\"}\"} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b5fd19f4-640e-48c4-b9b1-6b43f06f0f11\",\"trace_id\":\"bc736589-625e-4204-9071-f5f2f7da8d99\"}\n[2026-05-11 10:24:27] local.INFO: [RetryFailedDownloads] Starting {\"options\":{\"from\":null,\"to\":null,\"help\":false,\"silent\":false,\"quiet\":false,\"verbose\":false,\"version\":false,\"ansi\":null,\"no-interaction\":false,\"env\":null}} {\"correlation_id\":\"be1dd357-8994-4b0b-a8e9-f0e7dafe0552\",\"trace_id\":\"b203fd86-cf8b-48c1-a8fb-27ccfe131915\"}\n[2026-05-11 10:25:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3a3ff15c-a907-4597-81c7-53ec1e031983\",\"trace_id\":\"b2f88f98-695d-4635-bfc6-073441408e19\"}\n[2026-05-11 10:25:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"3a3ff15c-a907-4597-81c7-53ec1e031983\",\"trace_id\":\"b2f88f98-695d-4635-bfc6-073441408e19\"}\n[2026-05-11 10:25:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3a3ff15c-a907-4597-81c7-53ec1e031983\",\"trace_id\":\"b2f88f98-695d-4635-bfc6-073441408e19\"}\n[2026-05-11 10:25:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"87f7d7be-b29a-44cc-95db-bc343d1ddc4d\",\"trace_id\":\"6ecc6296-beac-4c8c-8006-2056fb88a912\"}\n[2026-05-11 10:25:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"87f7d7be-b29a-44cc-95db-bc343d1ddc4d\",\"trace_id\":\"6ecc6296-beac-4c8c-8006-2056fb88a912\"}\n[2026-05-11 10:25:13] local.NOTICE: Monitoring start {\"correlation_id\":\"f1f6f9a7-5ae2-4ad0-a221-5259028c26d8\",\"trace_id\":\"fe9ac124-0bcc-4c33-b3d8-bf136686198d\"}\n[2026-05-11 10:25:13] local.NOTICE: Monitoring end {\"correlation_id\":\"f1f6f9a7-5ae2-4ad0-a221-5259028c26d8\",\"trace_id\":\"fe9ac124-0bcc-4c33-b3d8-bf136686198d\"}\n[2026-05-11 10:25:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"13c7c749-aa45-400e-b448-cce1a5ad060d\",\"trace_id\":\"c6715ee4-640f-4933-a8b7-2e896f4a0592\"}\n[2026-05-11 10:25:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"13c7c749-aa45-400e-b448-cce1a5ad060d\",\"trace_id\":\"c6715ee4-640f-4933-a8b7-2e896f4a0592\"}\n[2026-05-11 10:25:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:19] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:19] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"58707af4-75ed-4d17-aae6-745738eca1a6\",\"trace_id\":\"f96c06a1-5d50-4f60-b812-36a2f80341a8\"}\n[2026-05-11 10:25:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6f625f7c-a2d8-4dab-9230-14a29e565aaa\",\"trace_id\":\"21afd870-871f-48f2-986b-94a4361a3aac\"}\n[2026-05-11 10:25:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6f625f7c-a2d8-4dab-9230-14a29e565aaa\",\"trace_id\":\"21afd870-871f-48f2-986b-94a4361a3aac\"}\n[2026-05-11 10:25:26] local.INFO: [HubSpot Webhook] Signature validation started {\"method\":\"POST\",\"uri\":\"/webhook/conference/hubspot/events\",\"has_v3_signature\":true,\"has_v1_signature\":true} {\"correlation_id\":\"ba3bd7f5-0487-4407-9c46-a117face1f00\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:26] local.INFO: [HubSpot Webhook] Event received {\"payload\":[{\"eventId\":3996584484,\"subscriptionId\":5683263,\"portalId\":4392066,\"appId\":38482,\"occurredAt\":1778472098068,\"subscriptionType\":\"company.propertyChange\",\"attemptNumber\":8,\"objectId\":52628776324,\"propertyName\":\"hubspot_owner_id\",\"propertyValue\":\"\",\"changeSource\":\"CRM_UI\",\"sourceId\":\"userId:45562061\"}],\"event_count\":1} {\"correlation_id\":\"ba3bd7f5-0487-4407-9c46-a117face1f00\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:26] local.INFO: [HubSpot Webhook Job] Processing webhook events {\"event_count\":1,\"local_count\":1,\"forward_count\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:26] local.INFO: [Webhook Forwarder] Forwarding to instance {\"url\":\"https://uranus.staging.jiminny.com/internal/webhook-receiver/hubspot\",\"route\":\"internal.webhook-receiver.hubspot\",\"event_count\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:27] local.ERROR: [Webhook Forwarder] Failed to forward to instance {\"url\":\"https://uranus.staging.jiminny.com\",\"route\":\"internal.webhook-receiver.hubspot\",\"error\":\"Server error: `POST https://uranus.staging.jiminny.com/internal/webhook-receiver/hubspot` resulted in a `503 Service Temporarily Unavailable` response:\n<html>\n\n<head><title>503 Service Temporarily Unavailable</title></head>\n\n<body>\n\n<center><h1>503 Service Temporarily Una (truncated...)\n\",\"code\":503} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:27] local.INFO: [Webhook Forwarder] Forwarding to instance {\"url\":\"https://app.qai.jiminny.com/internal/webhook-receiver/hubspot\",\"route\":\"internal.webhook-receiver.hubspot\",\"event_count\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: [Webhook Forwarder] Successfully forwarded to instance {\"url\":\"https://app.qai.jiminny.com/internal/webhook-receiver/hubspot\",\"status_code\":202,\"response\":{\"status\":\"accepted\",\"message\":\"Events queued for processing\",\"event_count\":1}} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: [HubSpot Webhook] Processing property change event {\"event_type\":\"company.propertyChange\",\"object_id\":52628776324,\"portal_id\":4392066,\"property_name\":\"hubspot_owner_id\",\"property_value\":\"\",\"team_id\":2} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: [BatchSyncCollector] Stored webhook in Redis {\"object_type\":\"company\",\"crm_provider_id\":\"52628776324\",\"event_type\":\"property_change\",\"configuration_id\":2,\"batch_key\":\"batch_sync_company:ids:2:all\",\"was_new\":true,\"current_size\":1} {\"correlation_id\":\"d34cfb4a-440b-4f62-8c00-eb2e0653c275\",\"trace_id\":\"cebfb66b-f4f6-4bd5-932c-5e429e77dcb1\"}\n[2026-05-11 10:25:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b2945a08-0aa8-4188-a54e-ebbd99af3536\",\"trace_id\":\"cda58daa-be85-4685-bcaf-fee37ff980b0\"}\n[2026-05-11 10:25:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b2945a08-0aa8-4188-a54e-ebbd99af3536\",\"trace_id\":\"cda58daa-be85-4685-bcaf-fee37ff980b0\"}\n[2026-05-11 10:25:31] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"adb456f4-ddb9-41f8-b32e-99fe065d7b96\",\"trace_id\":\"72c5e7e0-897d-4fe8-9870-46360bfaad50\"}\n[2026-05-11 10:25:31] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"adb456f4-ddb9-41f8-b32e-99fe065d7b96\",\"trace_id\":\"72c5e7e0-897d-4fe8-9870-46360bfaad50\"}\n[2026-05-11 10:25:31] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"adb456f4-ddb9-41f8-b32e-99fe065d7b96\",\"trace_id\":\"72c5e7e0-897d-4fe8-9870-46360bfaad50\"}\n[2026-05-11 10:25:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:33] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:15:00, 2026-05-11 10:20:00] {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:33] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:15:00, 2026-05-11 10:20:00] {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fe2fd25a-7950-47e9-9473-64860577705f\",\"trace_id\":\"9bd94165-e43d-40aa-840b-5726f19ad4d9\"}\n[2026-05-11 10:25:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:36] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:20\",\"to\":\"10:25\"} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:36] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:15\",\"to\":\"00:20\"} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:36] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b046c3f7-6327-496e-941d-ee0bcfee144d\",\"trace_id\":\"583c0e10-f5b7-47e1-8cff-cbb518ce9101\"}\n[2026-05-11 10:25:42] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:42] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:43] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"d254c3c1-d745-424c-9d9b-d789bac84abd\",\"trace_id\":\"8ad9716a-bfcb-4143-a7b2-bfe1162147eb\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a32adbf6-c09d-4d9c-983f-5be6f0ce6513\",\"trace_id\":\"7986b833-6171-4907-90a7-405a30938b33\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c579e1ac-b1aa-4530-bfbe-446399c34ed7\",\"trace_id\":\"1188f284-932b-4f41-953a-c141ee01e928\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:27:48.421391Z\"} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c579e1ac-b1aa-4530-bfbe-446399c34ed7\",\"trace_id\":\"1188f284-932b-4f41-953a-c141ee01e928\"}\n[2026-05-11 10:25:48] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a32adbf6-c09d-4d9c-983f-5be6f0ce6513\",\"trace_id\":\"7986b833-6171-4907-90a7-405a30938b33\"}\n[2026-05-11 10:25:48] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:54] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:25:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ceb0c5d9-7814-4b15-b86b-9219d218ff94\",\"trace_id\":\"9ab3de82-63b8-4bcc-b7d0-10b01190b029\"}\n[2026-05-11 10:26:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"ceb0c5d9-7814-4b15-b86b-9219d218ff94\",\"trace_id\":\"9ab3de82-63b8-4bcc-b7d0-10b01190b029\"}\n[2026-05-11 10:26:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ceb0c5d9-7814-4b15-b86b-9219d218ff94\",\"trace_id\":\"9ab3de82-63b8-4bcc-b7d0-10b01190b029\"}\n[2026-05-11 10:26:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d46ad7d9-64f7-43a0-9684-4b23ef6c811b\",\"trace_id\":\"2b474f1c-c197-4566-9bbc-1808f88f2fff\"}\n[2026-05-11 10:26:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d46ad7d9-64f7-43a0-9684-4b23ef6c811b\",\"trace_id\":\"2b474f1c-c197-4566-9bbc-1808f88f2fff\"}\n[2026-05-11 10:26:12] local.NOTICE: Monitoring start {\"correlation_id\":\"560c552d-93de-4e0b-b2df-732961322f44\",\"trace_id\":\"234c1c50-a070-4bda-be52-b55d2928120b\"}\n[2026-05-11 10:26:12] local.NOTICE: Monitoring end {\"correlation_id\":\"560c552d-93de-4e0b-b2df-732961322f44\",\"trace_id\":\"234c1c50-a070-4bda-be52-b55d2928120b\"}\n[2026-05-11 10:26:14] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b06f3e7a-d18d-4f1a-bc13-eab0a626e8fc\",\"trace_id\":\"d178ac51-c26f-41af-952c-892796fa9a7d\"}\n[2026-05-11 10:26:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b06f3e7a-d18d-4f1a-bc13-eab0a626e8fc\",\"trace_id\":\"d178ac51-c26f-41af-952c-892796fa9a7d\"}\n[2026-05-11 10:26:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:17] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:17] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a2fa74c2-dde2-44b9-8d18-50985a7c2f56\",\"trace_id\":\"2226e461-5395-4b43-a494-4adf4b94a156\"}\n[2026-05-11 10:26:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:19] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:24:00, 2026-05-11 10:26:00] {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:20] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:24:00, 2026-05-11 10:26:00] {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3fb802a5-89c6-4abb-8f3f-83201fcbad6b\",\"trace_id\":\"039ca277-230f-4d98-af90-dca6e5d6ead8\"}\n[2026-05-11 10:26:23] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"bef61b4f-9a53-43fd-a038-f57aea589c46\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"bef61b4f-9a53-43fd-a038-f57aea589c46\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24406712,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":109.34,\"usage\":24468752,\"real_usage\":62914560,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"9c424704-f37f-42e8-b8f5-0b314f58e67e\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24426968,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [BatchSyncRedisService] Reset meta batch {\"config_id\":2,\"object_type\":\"company\",\"event_type\":\"all\",\"meta_key\":\"batch_sync_company:meta:2:all\",\"reset_at\":1778495184} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [WebhookSyncBatchProcessor] Batch processing completed {\"object_type\":\"company\",\"config_id\":2,\"total_dispatched\":1,\"batches_dispatched\":1} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:24] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.5,\"average_seconds_per_request\":0.5} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":548.45} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":747.22,\"usage\":24492704,\"real_usage\":62914560,\"pid\":62058} {\"correlation_id\":\"89dd2b11-11e0-42d2-bee1-1240d6096339\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:25] local.INFO: [ImportAccountBatch] Processing batch {\"crmConfigurationId\":2,\"batchSize\":1} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [HubSpot] Batch fetched companies {\"requested_count\":1,\"returned_count\":1,\"crm_ids\":[\"52628776324\"]} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [HubSpot] importAccount {\"crm_provider_id\":\"52628776324\",\"config_id\":2} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [HubSpot] importAccountBatch timing {\"teamId\":2,\"account_count\":1,\"requested_count\":1,\"not_found_count\":0,\"total_ms\":778,\"fetch_api_ms\":737,\"accounts_loop_ms\":40,\"avg_account_ms\":40,\"slow_accounts_count\":0,\"slow_accounts\":[]} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [ImportAccountBatch] Batch completed {\"crmConfigurationId\":2,\"success\":1,\"failed\":0,\"skipped\":0,\"requested\":1,\"processed\":1,\"duration_ms\":779.26} {\"correlation_id\":\"b43ccd53-1cf9-4500-be09-e3333c6de005\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24651424,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":51.35,\"usage\":24654912,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"3f85fdb4-49d7-4307-886f-380edb245111\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24615552,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:26] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":30.26,\"usage\":24658496,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"5ce5607d-8093-42f8-9e7b-9a3483fb79fe\",\"trace_id\":\"2c4c3491-0341-4f36-af58-c395d80cfeaa\"}\n[2026-05-11 10:26:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"4e1f70b0-9d56-410c-9032-413bf9893d77\",\"trace_id\":\"0095fb60-0f43-4f5e-8ac7-20bccd3437be\"}\n[2026-05-11 10:26:29] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"4e1f70b0-9d56-410c-9032-413bf9893d77\",\"trace_id\":\"0095fb60-0f43-4f5e-8ac7-20bccd3437be\"}\n[2026-05-11 10:26:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:34] local.INFO: [EmailSchedule] STARTING Inbox Sync {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:34] local.INFO: [EmailSchedule] FINISHED Inbox Sync {\"host\":\"docker_lamp_1\",\"events\":2} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f43405a1-87e3-4ad7-8494-c9100ac1fc10\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":59} {\"correlation_id\":\"4f907293-a2ce-4136-b8cb-8d41c4462d35\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 59 due to unauthorized access to the mailbox {\"correlation_id\":\"4f907293-a2ce-4136-b8cb-8d41c4462d35\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":59} {\"correlation_id\":\"4f907293-a2ce-4136-b8cb-8d41c4462d35\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":212} {\"correlation_id\":\"514c7e78-20b5-4f67-bf77-479acd3e08f1\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 212 due to unauthorized access to the mailbox {\"correlation_id\":\"514c7e78-20b5-4f67-bf77-479acd3e08f1\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:37] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":212} {\"correlation_id\":\"514c7e78-20b5-4f67-bf77-479acd3e08f1\",\"trace_id\":\"68be7999-73af-40a9-bf17-beec06b3e585\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":57,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":280.4,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:26:45] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"3bf74d28-0d84-4e53-b8f0-5b2af9e8a98d\",\"trace_id\":\"c8b388e1-da4f-4e29-aa97-80df9c70409c\"}\n[2026-05-11 10:27:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0fa8e2ca-02d1-445d-8926-f63d538d158c\",\"trace_id\":\"4f40000b-4fd4-4f41-9b87-c3a75f103f0b\"}\n[2026-05-11 10:27:09] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"0fa8e2ca-02d1-445d-8926-f63d538d158c\",\"trace_id\":\"4f40000b-4fd4-4f41-9b87-c3a75f103f0b\"}\n[2026-05-11 10:27:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0fa8e2ca-02d1-445d-8926-f63d538d158c\",\"trace_id\":\"4f40000b-4fd4-4f41-9b87-c3a75f103f0b\"}\n[2026-05-11 10:27:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"68148728-decd-43a7-9a08-87f059dc48f1\",\"trace_id\":\"e22a5080-2fb8-4f67-8416-0b879e20d8a2\"}\n[2026-05-11 10:27:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"68148728-decd-43a7-9a08-87f059dc48f1\",\"trace_id\":\"e22a5080-2fb8-4f67-8416-0b879e20d8a2\"}\n[2026-05-11 10:27:16] local.NOTICE: Monitoring start {\"correlation_id\":\"9cdfbf72-6c1e-4dc4-93ad-64856bbb0cd7\",\"trace_id\":\"81b03f94-7a43-44ba-9a59-eae3cc760b20\"}\n[2026-05-11 10:27:16] local.NOTICE: Monitoring end {\"correlation_id\":\"9cdfbf72-6c1e-4dc4-93ad-64856bbb0cd7\",\"trace_id\":\"81b03f94-7a43-44ba-9a59-eae3cc760b20\"}\n[2026-05-11 10:27:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6f75a1a9-292f-46e3-83d3-14ca3581ddb2\",\"trace_id\":\"909f3358-7a1d-4c9b-bcfb-f59f2e47fd47\"}\n[2026-05-11 10:27:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6f75a1a9-292f-46e3-83d3-14ca3581ddb2\",\"trace_id\":\"909f3358-7a1d-4c9b-bcfb-f59f2e47fd47\"}\n[2026-05-11 10:27:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:20] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:21] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1d07e6b7-05e0-4b7c-820c-0860f1b4cf5f\",\"trace_id\":\"eb5cfba7-3aee-4cb9-a365-bed536ca9b4c\"}\n[2026-05-11 10:27:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:24] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:24] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"30b8a328-827f-4d5d-b314-5823b3645191\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:27:25] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"7921218f-5c01-44a0-8bfb-c6da1eaf2761\",\"trace_id\":\"c646e0b0-ec53-4329-9369-fa3be2760b7c\"}\n[2026-05-11 10:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"40689200-34eb-44dc-8734-2a7e4efe7f82\",\"trace_id\":\"b0f72776-b242-4f70-a188-92fa324dc525\"}\n[2026-05-11 10:28:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"40689200-34eb-44dc-8734-2a7e4efe7f82\",\"trace_id\":\"b0f72776-b242-4f70-a188-92fa324dc525\"}\n[2026-05-11 10:28:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"40689200-34eb-44dc-8734-2a7e4efe7f82\",\"trace_id\":\"b0f72776-b242-4f70-a188-92fa324dc525\"}\n[2026-05-11 10:28:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a79c351f-f63a-4942-b81a-f71a44ccd709\",\"trace_id\":\"ecfb945c-3c6f-414f-b45f-d17a477e626f\"}\n[2026-05-11 10:28:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a79c351f-f63a-4942-b81a-f71a44ccd709\",\"trace_id\":\"ecfb945c-3c6f-414f-b45f-d17a477e626f\"}\n[2026-05-11 10:28:10] local.NOTICE: Monitoring start {\"correlation_id\":\"49734034-a0b9-4576-a904-b0bfc2c8edf4\",\"trace_id\":\"de775bb9-3038-4bdc-8a4f-6a015c108223\"}\n[2026-05-11 10:28:11] local.NOTICE: Monitoring end {\"correlation_id\":\"49734034-a0b9-4576-a904-b0bfc2c8edf4\",\"trace_id\":\"de775bb9-3038-4bdc-8a4f-6a015c108223\"}\n[2026-05-11 10:28:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a65dee3f-09de-4601-af88-cc9df13d892f\",\"trace_id\":\"7795b9b5-f4d0-4d76-b1db-deb500a9779b\"}\n[2026-05-11 10:28:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a65dee3f-09de-4601-af88-cc9df13d892f\",\"trace_id\":\"7795b9b5-f4d0-4d76-b1db-deb500a9779b\"}\n[2026-05-11 10:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:22] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:22] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"48a5b60b-b2c0-4702-b1cc-020d8b75cbf1\",\"trace_id\":\"28dbd53f-681a-4d50-bab3-3182ea1a597f\"}\n[2026-05-11 10:28:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:26] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:26:00, 2026-05-11 10:28:00] {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:26] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:26:00, 2026-05-11 10:28:00] {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"545db49e-22e4-4154-adaf-8aea5d72f7f7\",\"trace_id\":\"003b3ee2-343f-4ec9-9111-8bfe3c6aa79c\"}\n[2026-05-11 10:28:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"7ec2c6bf-ee39-4528-931a-65adba7f71be\",\"trace_id\":\"99692240-2872-4e5c-9bcd-4288a252b7d1\"}\n[2026-05-11 10:28:34] local.NOTICE: Calendar sync start {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"7ec2c6bf-ee39-4528-931a-65adba7f71be\",\"trace_id\":\"99692240-2872-4e5c-9bcd-4288a252b7d1\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1393,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1393,\"provider\":\"google\",\"refreshToken\":\"5aa7e2d96b53201cd16fca5d2e4ef3ad03320971fc064781d18aee3ae7b99fbf\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1393,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1387,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1387,\"provider\":\"google\",\"refreshToken\":\"8157ac6de94842937194009e9c50e459253600f799dacf6a40755ffdbeb5bba6\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1387,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1348,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1348,\"provider\":\"google\",\"refreshToken\":\"9e7d13d3032d0cb1b79d8e95aef01383e8e91eb52ff8ee960c8a0b6b95cd8c73\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1348,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1361,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1361,\"provider\":\"google\",\"refreshToken\":\"6c843da199c2b9907445329304fcc4ec5057a4ee748d8299641764395c08e1fd\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1361,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1310,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1310,\"provider\":\"google\",\"refreshToken\":\"e34818922c2830a660813a63f6169a4a9a992ae2cccd7dc8dd7796cfdb470ef1\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1310,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1333,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1333,\"provider\":\"google\",\"refreshToken\":\"6c902986546d8e8da1dc539b046cdc1d458f519acc972e5b5f1d6a1a295165e0\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1333,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1368,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1368,\"provider\":\"google\",\"refreshToken\":\"d2f128898ff8543bd16b69cfae37896ab85119b0f5ed2b431d739593bb600333\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1368,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1365,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:35] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1365,\"provider\":\"google\",\"refreshToken\":\"7676e4a9afcd082b413248ab5ec6e487021fec6a9bdf315860a59cefad9caad8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1365,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1364,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1364,\"provider\":\"google\",\"refreshToken\":\"dd5882ebce76e645292ce33ae74238abbb77c0a4ecc6a2bfe723cad82e72ba8e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"responseBody\":{\"error\":\"unauthorized_client\",\"error_description\":\"Unauthorized\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1364,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1370,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1370,\"provider\":\"office\",\"refreshToken\":\"b7ee8035306d0043cea6e00e7c4fe14f745e44074a1194db62a31cdf8b70af3e\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 72dca194-9707-4e51-83a1-c87c97dc1800 Correlation ID: b3a75d57-64c2-48ff-a376-2c94d1bab535 Timestamp: 2026-05-11 10:28:36Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:36Z\\\",\\\"trace_id\\\":\\\"72dca194-9707-4e51-83a1-c87c97dc1800\\\",\\\"correlation_id\\\":\\\"b3a75d57-64c2-48ff-a376-2c94d1bab535\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1370,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1202,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:36] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1202,\"provider\":\"office\",\"refreshToken\":\"b458799ccc29b21a6e2eb5260fdb63e49ccba21bf942a3973fb63799bd7f0afe\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 10d1576d-0c9c-41ab-8f10-d27611d01f00 Correlation ID: 258f8dcc-012b-46af-b572-ac9a9fc203ad Timestamp: 2026-05-11 10:28:37Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:37Z\\\",\\\"trace_id\\\":\\\"10d1576d-0c9c-41ab-8f10-d27611d01f00\\\",\\\"correlation_id\\\":\\\"258f8dcc-012b-46af-b572-ac9a9fc203ad\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1202,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: Calendar sync job dispatched {\"calendar_id\":501} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1300,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1300,\"provider\":\"google\",\"refreshToken\":\"4b811db0725fd9602a95943519a7da935e2a5065da7d9ebfcb170752e3e1ddb8\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Account has been deleted\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1300,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1409,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1409,\"provider\":\"google\",\"refreshToken\":\"e2a3f2d06894894eed1ee87d9db1ace77d4d42ee6e1288a8940ad2c10333b0c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1409,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1352,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1352,\"provider\":\"google\",\"refreshToken\":\"dd4b16b00fdc1216da6b717c02338c073636e29162826b2de6db3f064fc029eb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Token has been expired or revoked.\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1352,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1296,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:37] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1296,\"provider\":\"office\",\"refreshToken\":\"011ae723c9d800c674e0b4be76f49fc046dac7d501b66c59ef0d9549cfa56ae5\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 9d674338-6e76-4e83-aca4-da73b67e1d00 Correlation ID: 3a4aff15-90cc-41a4-9b3f-c5162caec715 Timestamp: 2026-05-11 10:28:38Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:38Z\\\",\\\"trace_id\\\":\\\"9d674338-6e76-4e83-aca4-da73b67e1d00\\\",\\\"correlation_id\\\":\\\"3a4aff15-90cc-41a4-9b3f-c5162caec715\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1296,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":391,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:38] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":391,\"provider\":\"office\",\"refreshToken\":\"00045eebae0f39b34887c6d53f92ae78064f7145e1f4b67754aebd03cfb2d881\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: dc988698-5fac-4412-96aa-bcbd33ff2000 Correlation ID: 475197fc-db2f-4216-98d8-e092ad827d60 Timestamp: 2026-05-11 10:28:39Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:39Z\\\",\\\"trace_id\\\":\\\"dc988698-5fac-4412-96aa-bcbd33ff2000\\\",\\\"correlation_id\\\":\\\"475197fc-db2f-4216-98d8-e092ad827d60\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":391,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1271,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1271,\"provider\":\"office\",\"refreshToken\":\"118cde2c06993147b07ccaec4cbcd5026a819dea6c71081166a492933e392afb\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [Calendar] Processing sync {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"from\":null,\"to\":null,\"delta\":\"CIiFh8TP44kDEIiFh8TP44kDGAUgkZvkzgIokZvkzgI=\",\"last_sync\":\"2024-12-09 07:12:53\",\"dateMode\":\"daily\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"integration-app\",\"crm_owner\":1695,\"team_id\":3143} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1502,\"provider\":\"google\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"responseBody\":\"{\\\"error\\\":\\\"invalid_client\\\",\\\"error_description\\\":\\\"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app 'bbcbb2ef-6200-4fae-82bd-d81f5dd738da'. Trace ID: 4e60d43e-f26e-46ce-96df-0f7e57702500 Correlation ID: bb550866-1814-4ebf-9ff2-3916798900b9 Timestamp: 2026-05-11 10:28:39Z\\\",\\\"error_codes\\\":[7000215],\\\"timestamp\\\":\\\"2026-05-11 10:28:39Z\\\",\\\"trace_id\\\":\\\"4e60d43e-f26e-46ce-96df-0f7e57702500\\\",\\\"correlation_id\\\":\\\"bb550866-1814-4ebf-9ff2-3916798900b9\\\",\\\"error_uri\\\":\\\"https://login.microsoftonline.com/error?code=7000215\\\"}\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1271,\"provider\":\"office\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1351,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1351,\"provider\":\"google\",\"refreshToken\":\"4271d15b9e60a606439caddc68337f783e472c85b03dacff14d1b6dfded9051c\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1351,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1366,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1366,\"provider\":\"google\",\"refreshToken\":\"ae21385059b2eebfd43f68aecd56eccd702a1aabb6598f1f7ab594ed8af491b4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"a33076c1-8d97-431a-99f0-85c9524e118b\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"fcfbf03b-894a-46f6-b12a-a137a46766bc\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"responseBody\":{\"error\":\"invalid_grant\",\"error_description\":\"Bad Request\"}} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.ERROR: [SocialAccountService] Failed to refresh token {\"socialAccountId\":1366,\"provider\":\"google\",\"reason\":\"Flow refresh required.\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: Calendar sync job dispatched {\"calendar_id\":378} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: Calendar sync job dispatched {\"calendar_id\":504} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.NOTICE: Calendar sync end {\"retrieved_calendars\":31,\"processed_calendars\":3} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"calendar:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"6c9433cf-203d-4e61-a4d4-ffc433737494\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [Calendar] Processing sync {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"from\":null,\"to\":null,\"delta\":\"CJ_x49O3jpIDEJ_x49O3jpIDGAUgw67KlwMow67KlwM=\",\"last_sync\":\"2026-01-19 07:48:40\",\"dateMode\":\"daily\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.WARNING: [Pipedrive] Account not connected for user {\"userId\":\"e6538737-e7b4-455f-a37a-3e79b665a220\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1116,\"sociable_id\":241,\"provider_user_id\":\"19555731\",\"expires\":1775683749,\"refresh_token_expires\":null,\"provider\":\"pipedrive\",\"state\":\"full-refresh\",\"auth_scope\":\"base,deals:full,activities:full,contacts:full,search:read\",\"retry_after\":null,\"created_at\":\"2023-09-08 09:44:29\",\"updated_at\":\"2026-04-08 22:58:34\"}}} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"pipedrive\",\"crm_owner\":241,\"team_id\":19} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"pipedrive\",\"team_id\":19} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.WARNING: [Calendar] CRM disconnected for user so events will not be matched {\"provider\":\"pipedrive\",\"user_id\":241,\"message\":\"Your Pipedrive account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1115,\"provider\":\"google\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:41] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [Google Calendar] Failed to watch channel for calendar {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.WARNING: [Calendar] Sync failed {\"calendarId\":\"2676cb6d-f86c-427e-bf78-591e388e3c1e\",\"code\":400,\"reason\":\"{\n \\\"error\\\": {\n \\\"errors\\\": [\n {\n \\\"domain\\\": \\\"global\\\",\n \\\"reason\\\": \\\"push.webhookUrlNotHttps\\\",\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n ],\n \\\"code\\\": 400,\n \\\"message\\\": \\\"WebHook callback must be HTTPS: /webhook/calendar/google?resourceType=event\\\"\n }\n}\"} {\"correlation_id\":\"2860dbef-ee6f-4551-b665-6b2b10afaa96\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1421,\"provider\":\"office\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [Calendar] Processing sync {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\",\"from\":null,\"to\":null,\"delta\":\"R0usmcdvmMuZCBYV0hguCLlvcOB4kXlhlC7KgH1SnZwTrZ3faZv1fXPQqJhxe_L9AxWWlb-wASsjGiiWlhsBUg9MFb3ZdlAYerVV_ZirRPbsKWCxEXhybD90arJmok_M4ecGFUQ9_BIGu-c6RAnJy2TRKZ7gPTsJi_8TGceGAuqimlhm4G4mjDLvYVVwImjjU7M3xJvUzL47dLOGNTJCww.k1TST0VEYCgbFOkwa3ysYMi100FtVfkzfqlXLnV6gPg\",\"last_sync\":\"2026-05-11 06:13:36\",\"dateMode\":\"daily\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:28:42] local.INFO: [MS Office Calendar] Skipping delta sync for daily mode {\"calendarId\":\"9e8b1a2c-1a8f-42bd-b161-810fc0baf540\"} {\"correlation_id\":\"69dd4b83-93ee-4dfa-bbdc-625bdbe77676\",\"trace_id\":\"873c228e-f5dc-45b0-9b16-8ce4a7348f1c\"}\n[2026-05-11 10:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0465eb00-6e46-4718-af63-3e39a581fe31\",\"trace_id\":\"7410dc20-61f5-466f-b207-731d3b5a8f9c\"}\n[2026-05-11 10:29:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"0465eb00-6e46-4718-af63-3e39a581fe31\",\"trace_id\":\"7410dc20-61f5-466f-b207-731d3b5a8f9c\"}\n[2026-05-11 10:29:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0465eb00-6e46-4718-af63-3e39a581fe31\",\"trace_id\":\"7410dc20-61f5-466f-b207-731d3b5a8f9c\"}\n[2026-05-11 10:29:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"54350d90-7959-4b7e-b190-24ca14a2e28f\",\"trace_id\":\"90339d05-d9db-4a22-ac90-bcf8d2855cb1\"}\n[2026-05-11 10:29:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"54350d90-7959-4b7e-b190-24ca14a2e28f\",\"trace_id\":\"90339d05-d9db-4a22-ac90-bcf8d2855cb1\"}\n[2026-05-11 10:29:08] local.NOTICE: Monitoring start {\"correlation_id\":\"6cb6c4e6-5b94-4a35-95b9-d0da3e00b0f4\",\"trace_id\":\"d035104f-576f-40f5-8a4a-9c8b0e339b74\"}\n[2026-05-11 10:29:08] local.NOTICE: Monitoring end {\"correlation_id\":\"6cb6c4e6-5b94-4a35-95b9-d0da3e00b0f4\",\"trace_id\":\"d035104f-576f-40f5-8a4a-9c8b0e339b74\"}\n[2026-05-11 10:29:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"17f41c15-8b7a-4042-b2cf-b4989d7bec56\",\"trace_id\":\"ebf0f7cf-dccb-41de-a5c3-540cbd34be35\"}\n[2026-05-11 10:29:09] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"17f41c15-8b7a-4042-b2cf-b4989d7bec56\",\"trace_id\":\"ebf0f7cf-dccb-41de-a5c3-540cbd34be35\"}\n[2026-05-11 10:29:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:29:11] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:29:11] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:29:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a8cfde97-88cf-44ce-917d-33f252aa8763\",\"trace_id\":\"df3a50f8-5405-42af-9d92-a51231a7bbf9\"}\n[2026-05-11 10:30:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2aba99d8-c58b-447d-9817-1a5a9504fef5\",\"trace_id\":\"e2ffb579-ceae-406d-9a7f-08b872c99d53\"}\n[2026-05-11 10:30:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"2aba99d8-c58b-447d-9817-1a5a9504fef5\",\"trace_id\":\"e2ffb579-ceae-406d-9a7f-08b872c99d53\"}\n[2026-05-11 10:30:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2aba99d8-c58b-447d-9817-1a5a9504fef5\",\"trace_id\":\"e2ffb579-ceae-406d-9a7f-08b872c99d53\"}\n[2026-05-11 10:30:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e2cf0fc5-2d3f-46d9-b39d-a9beab9df260\",\"trace_id\":\"c5fda48b-3876-47c1-8186-64cce7e053eb\"}\n[2026-05-11 10:30:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e2cf0fc5-2d3f-46d9-b39d-a9beab9df260\",\"trace_id\":\"c5fda48b-3876-47c1-8186-64cce7e053eb\"}\n[2026-05-11 10:30:10] local.NOTICE: Monitoring start {\"correlation_id\":\"4ae14f41-e60e-4136-8839-1d1fd0daaf12\",\"trace_id\":\"1afb6ea3-fcc0-41bc-836c-504edc28e986\"}\n[2026-05-11 10:30:10] local.NOTICE: Monitoring end {\"correlation_id\":\"4ae14f41-e60e-4136-8839-1d1fd0daaf12\",\"trace_id\":\"1afb6ea3-fcc0-41bc-836c-504edc28e986\"}\n[2026-05-11 10:30:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"bd56adee-a96c-4f21-81ec-b7543cb5492b\",\"trace_id\":\"968bf9e5-04a2-4236-8db5-5ec33bd01f07\"}\n[2026-05-11 10:30:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"bd56adee-a96c-4f21-81ec-b7543cb5492b\",\"trace_id\":\"968bf9e5-04a2-4236-8db5-5ec33bd01f07\"}\n[2026-05-11 10:30:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:13] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:13] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c68128d7-fa77-4778-9253-988920beb37b\",\"trace_id\":\"3dc268ef-7ab1-49a7-8197-0ca57d33c0bd\"}\n[2026-05-11 10:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:28:00, 2026-05-11 10:30:00] {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:28:00, 2026-05-11 10:30:00] {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1f2a8e42-13b8-4134-8393-a3ca86bd357a\",\"trace_id\":\"9079a30e-b850-4cac-9319-2acbbea57477\"}\n[2026-05-11 10:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"02dff32b-488e-43e8-ac22-709dea182f79\",\"trace_id\":\"4bb34b12-3c2c-4705-bf96-7c52086432be\"}\n[2026-05-11 10:30:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"02dff32b-488e-43e8-ac22-709dea182f79\",\"trace_id\":\"4bb34b12-3c2c-4705-bf96-7c52086432be\"}\n[2026-05-11 10:30:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a5991b76-81d9-4f65-aaac-699d006f1042\",\"trace_id\":\"1b29b5dc-ceae-4cee-84de-47550a07d9d4\"}\n[2026-05-11 10:30:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a5991b76-81d9-4f65-aaac-699d006f1042\",\"trace_id\":\"1b29b5dc-ceae-4cee-84de-47550a07d9d4\"}\n[2026-05-11 10:30:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"381abaee-2e1c-4372-a476-e2eae2dca7ce\",\"trace_id\":\"048ab219-e61e-4a62-8bd7-6f50ba180460\"}\n[2026-05-11 10:30:21] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"381abaee-2e1c-4372-a476-e2eae2dca7ce\",\"trace_id\":\"048ab219-e61e-4a62-8bd7-6f50ba180460\"}\n[2026-05-11 10:30:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"381abaee-2e1c-4372-a476-e2eae2dca7ce\",\"trace_id\":\"048ab219-e61e-4a62-8bd7-6f50ba180460\"}\n[2026-05-11 10:30:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:24] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:20:00, 2026-05-11 10:25:00] {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:24] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:20:00, 2026-05-11 10:25:00] {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"999a521d-fce3-4463-aac2-515e6dfbb29e\",\"trace_id\":\"5d38881f-ab33-4ba9-bd21-2083ec13c42b\"}\n[2026-05-11 10:30:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:25] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:25\",\"to\":\"10:30\"} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:25] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:20\",\"to\":\"00:25\"} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0537ae27-9238-413d-ad46-2f192fe4ccfa\",\"trace_id\":\"d5a38685-afee-4ac1-be85-a0c7f97793a8\"}\n[2026-05-11 10:30:27] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:27] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:27] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:27] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:28] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"61101965-3c09-4aee-9171-f7af9cc92e45\",\"trace_id\":\"6932e09f-e686-4bea-923a-1a6099f416ff\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"82ba3881-bffd-4764-96dd-3d22f9b2a3c9\",\"trace_id\":\"ec98b699-f5f0-4635-9ab1-f8bd359a0ab4\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"07e31516-7a25-4b7b-99b5-f4d215235639\",\"trace_id\":\"bd9719aa-9cb7-49a1-abcd-e22fb29d7ecb\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:32:33.541224Z\"} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:transcription:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"82ba3881-bffd-4764-96dd-3d22f9b2a3c9\",\"trace_id\":\"ec98b699-f5f0-4635-9ab1-f8bd359a0ab4\"}\n[2026-05-11 10:30:33] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"07e31516-7a25-4b7b-99b5-f4d215235639\",\"trace_id\":\"bd9719aa-9cb7-49a1-abcd-e22fb29d7ecb\"}\n[2026-05-11 10:30:33] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:38] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ecbaf403-a353-439c-aa9a-8223c91e98a8\",\"trace_id\":\"1d352c76-5c34-4632-9bab-ec97702746aa\"}\n[2026-05-11 10:30:38] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:reset-governor\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ecbaf403-a353-439c-aa9a-8223c91e98a8\",\"trace_id\":\"1d352c76-5c34-4632-9bab-ec97702746aa\"}\n[2026-05-11 10:30:39] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812688,\"provider\":\"twilio-flex\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812689,\"provider\":\"xant\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812690,\"provider\":\"apollo\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812691,\"provider\":\"groove\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812692,\"provider\":\"twilio-video\",\"team\":\"jiminny\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Dispatching activity sync job {\"import_id\":812693,\"provider\":\"hubspot\",\"team\":\"hubspot\"} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:42] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3bffa1ed-6310-47ba-8847-6544d193f092\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:44] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b12822e6-6528-42d6-998c-8bb26e197d8e\",\"trace_id\":\"577073db-3d72-41ba-ba6c-7a6952649f23\"}\n[2026-05-11 10:30:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:fail-stalled\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b12822e6-6528-42d6-998c-8bb26e197d8e\",\"trace_id\":\"577073db-3d72-41ba-ba6c-7a6952649f23\"}\n[2026-05-11 10:30:45] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf8b554-d951-4758-bc2b-c1b85d1cd0b9\",\"account\":null} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":3,\"team_id\":1} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.ALERT: [SyncActivity] Failed {\"import_id\":812688,\"provider\":\"twilio-flex\",\"provider_id\":317,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Social account for Salesforce cannot be found. Please login to Jiminny to connect.\",\"file\":\"/home/jiminny/app/Services/Crm/BaseService.php\",\"line\":646} {\"correlation_id\":\"c07b663c-7ab8-4930-b069-d9ea4bcff241\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:45] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.ALERT: [SyncActivity] Failed {\"import_id\":812689,\"provider\":\"xant\",\"provider_id\":161,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"1bf26202-1157-4c56-8ce7-9141c6abf14c\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.ALERT: [SyncActivity] Failed {\"import_id\":812690,\"provider\":\"apollo\",\"provider_id\":441,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"3a887dcc-3c83-430c-85e0-a89211ea1216\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:46] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.ALERT: [SyncActivity] Failed {\"import_id\":812691,\"provider\":\"groove\",\"provider_id\":228,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"55f06322-2557-414c-a97f-d0575363c594\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1173,\"provider\":\"salesforce\"} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e9e81669-de7e-44a6-948e-fbaf5cebc63b\",\"trace_id\":\"41d48720-ec10-4f33-94d2-c73160baecca\"}\n[2026-05-11 10:30:47] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e9e81669-de7e-44a6-948e-fbaf5cebc63b\",\"trace_id\":\"41d48720-ec10-4f33-94d2-c73160baecca\"}\n[2026-05-11 10:30:47] local.ALERT: [SyncActivity] Failed {\"import_id\":812692,\"provider\":\"twilio-video\",\"provider_id\":243,\"team\":\"jiminny\",\"team_id\":1,\"reason\":\"Activity Provider account not connected.\",\"file\":\"/home/jiminny/app/Services/Activity/ActivityProviderService.php\",\"line\":174} {\"correlation_id\":\"6803462d-7ee6-490e-ab6d-4aa48c2b7203\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":89,\"team_id\":2} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":408,\"provider\":\"hubspot\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [SyncActivity] Start {\"import_id\":812693,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:47] local.INFO: [HubSpot] Search calls for period {\"from\":\"2026-05-11 10:14:00\",\"to\":\"2026-05-11 10:30:00\"} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:48] local.INFO: [SyncActivity] End {\"import_id\":812693,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:48] local.INFO: [SyncActivity] Memory usage {\"import_id\":812693,\"provider\":\"hubspot\",\"provider_id\":31,\"team\":\"hubspot\",\"team_id\":2,\"memory_usage\":27211224,\"memory_real_usage\":65011712,\"pid\":62066} {\"correlation_id\":\"8e138568-838d-41eb-be4e-7636f43d2cb6\",\"trace_id\":\"757053cb-04ce-4b42-88aa-c37d02e2a84e\"}\n[2026-05-11 10:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fa96f49d-52b5-4148-9132-e4e06f25f718\",\"trace_id\":\"16188812-4089-42eb-93b1-1acc50370f56\"}\n[2026-05-11 10:30:50] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"nudges:send\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fa96f49d-52b5-4148-9132-e4e06f25f718\",\"trace_id\":\"16188812-4089-42eb-93b1-1acc50370f56\"}\n[2026-05-11 10:30:52] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:53] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] starting. {\"playlists\":[]} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:53] local.INFO: [Jiminny\\Component\\Playlist\\Command\\NormalizeSortCommand::handle] finished. {\"normalizedPlaylists\":[],\"deletedPlaylists\":[]} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"jiminny:playlists:normalize-sort\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8acb652e-9249-41b1-9735-6d2e9f489420\",\"trace_id\":\"cb9cabc5-919e-4a97-8cc2-c472f6e9e1ee\"}\n[2026-05-11 10:30:59] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f36d88f7-e68e-4e33-ae1b-8cff0800fd43\",\"trace_id\":\"a8818078-09e1-42fc-b8fb-767f172228bd\"}\n[2026-05-11 10:31:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"f36d88f7-e68e-4e33-ae1b-8cff0800fd43\",\"trace_id\":\"a8818078-09e1-42fc-b8fb-767f172228bd\"}\n[2026-05-11 10:31:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f36d88f7-e68e-4e33-ae1b-8cff0800fd43\",\"trace_id\":\"a8818078-09e1-42fc-b8fb-767f172228bd\"}\n[2026-05-11 10:31:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f38ba408-a4ad-45de-810a-b180a32b02be\",\"trace_id\":\"16fc212f-055e-4cf4-916c-2400e311426d\"}\n[2026-05-11 10:31:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f38ba408-a4ad-45de-810a-b180a32b02be\",\"trace_id\":\"16fc212f-055e-4cf4-916c-2400e311426d\"}\n[2026-05-11 10:31:11] local.NOTICE: Monitoring start {\"correlation_id\":\"38529cdf-db5d-486c-abe3-974e92c4eaa5\",\"trace_id\":\"61b274d5-6524-48ff-b90d-192ba1b785a5\"}\n[2026-05-11 10:31:11] local.NOTICE: Monitoring end {\"correlation_id\":\"38529cdf-db5d-486c-abe3-974e92c4eaa5\",\"trace_id\":\"61b274d5-6524-48ff-b90d-192ba1b785a5\"}\n[2026-05-11 10:31:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"eaecf0f8-8839-496f-a8f7-ae98023db10b\",\"trace_id\":\"e78bc97b-95c9-49da-a246-4478b6548da3\"}\n[2026-05-11 10:31:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"eaecf0f8-8839-496f-a8f7-ae98023db10b\",\"trace_id\":\"e78bc97b-95c9-49da-a246-4478b6548da3\"}\n[2026-05-11 10:31:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:15] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:15] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a92262d0-a5db-4a50-97a9-0f07aa552144\",\"trace_id\":\"653a4076-820d-426f-90b4-507ff31636c9\"}\n[2026-05-11 10:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8d9db40e-4c42-47db-87e4-d37956e23b49\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8d9db40e-4c42-47db-87e4-d37956e23b49\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24619888,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.23,\"average_seconds_per_request\":0.23} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":231.27} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":247.33,\"usage\":24703856,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"67580cdf-7989-4d45-9aae-b47039573313\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24681856,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":5.67,\"usage\":24692584,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"a7488b32-855d-46ef-9356-eec086db9c16\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24650088,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":13.16,\"usage\":24669792,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"495d37a2-22f5-4a6f-82cd-0b6dc60cd950\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24630472,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:19] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":18.34,\"usage\":24666208,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"76bbf66a-470c-4931-afcb-2ac3f5f93d77\",\"trace_id\":\"c29092d8-f4b2-4b34-a2d2-20cf54b1ecec\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":56,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":189.1,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:31:29] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"632b659b-821b-4068-bbc8-1662014b90a5\",\"trace_id\":\"14c147ce-44fc-4fe9-a47c-9fc8534c94d5\"}\n[2026-05-11 10:32:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"99ed83ef-ed2e-4a1b-b555-347028040d09\",\"trace_id\":\"1e916484-3166-436d-ab5e-477ef647ac93\"}\n[2026-05-11 10:32:17] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"99ed83ef-ed2e-4a1b-b555-347028040d09\",\"trace_id\":\"1e916484-3166-436d-ab5e-477ef647ac93\"}\n[2026-05-11 10:32:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"99ed83ef-ed2e-4a1b-b555-347028040d09\",\"trace_id\":\"1e916484-3166-436d-ab5e-477ef647ac93\"}\n[2026-05-11 10:32:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ff92f4cc-9fa1-48f4-8132-e7ad945cbc0f\",\"trace_id\":\"30333ea5-961b-48cd-b5db-60a2f101baaa\"}\n[2026-05-11 10:32:24] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ff92f4cc-9fa1-48f4-8132-e7ad945cbc0f\",\"trace_id\":\"30333ea5-961b-48cd-b5db-60a2f101baaa\"}\n[2026-05-11 10:32:28] local.NOTICE: Monitoring start {\"correlation_id\":\"8770e909-fa53-41ff-92a2-476d237422fd\",\"trace_id\":\"e3a38637-5e1f-46c9-b0cd-221f7c2133d5\"}\n[2026-05-11 10:32:28] local.NOTICE: Monitoring end {\"correlation_id\":\"8770e909-fa53-41ff-92a2-476d237422fd\",\"trace_id\":\"e3a38637-5e1f-46c9-b0cd-221f7c2133d5\"}\n[2026-05-11 10:32:34] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c36b230c-d92e-4f13-b57c-69b13f36794c\",\"trace_id\":\"ddf0dc75-7947-47f4-afe2-5ce286f8925e\"}\n[2026-05-11 10:32:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c36b230c-d92e-4f13-b57c-69b13f36794c\",\"trace_id\":\"ddf0dc75-7947-47f4-afe2-5ce286f8925e\"}\n[2026-05-11 10:32:39] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:39] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:40] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e20245bc-abeb-448b-8ca2-e8924b68ebe5\",\"trace_id\":\"a3ef8eef-726f-41cd-8358-c745fa5cb153\"}\n[2026-05-11 10:32:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:44] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:30:00, 2026-05-11 10:32:00] {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:44] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:30:00, 2026-05-11 10:32:00] {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:44] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a692796f-5cd1-4e26-9ef3-4aaf9dfc4f2a\",\"trace_id\":\"61ac6e5f-51ac-4518-99f7-68746e32051e\"}\n[2026-05-11 10:32:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0b3ffeb0-b2fd-4f1a-8498-8f4155488dac\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:32:46] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"95652e88-1c5d-45a7-b3c0-2bab2f761d8a\",\"trace_id\":\"a5a2f2e7-4169-4fa6-8e12-588de6c3830e\"}\n[2026-05-11 10:33:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"7af2c981-e735-4da9-83e1-79395f195e41\",\"trace_id\":\"31cad47b-63cf-48ba-a06f-98ecbaa5c683\"}\n[2026-05-11 10:33:11] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"7af2c981-e735-4da9-83e1-79395f195e41\",\"trace_id\":\"31cad47b-63cf-48ba-a06f-98ecbaa5c683\"}\n[2026-05-11 10:33:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"7af2c981-e735-4da9-83e1-79395f195e41\",\"trace_id\":\"31cad47b-63cf-48ba-a06f-98ecbaa5c683\"}\n[2026-05-11 10:33:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e9ca3026-0b79-43b7-b8a0-de3a719f35d7\",\"trace_id\":\"a594cb67-5fee-4b2e-9acd-ac8c20585296\"}\n[2026-05-11 10:33:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e9ca3026-0b79-43b7-b8a0-de3a719f35d7\",\"trace_id\":\"a594cb67-5fee-4b2e-9acd-ac8c20585296\"}\n[2026-05-11 10:33:18] local.NOTICE: Monitoring start {\"correlation_id\":\"accf51c2-9f23-46e6-b225-198a661828b3\",\"trace_id\":\"0e5ff218-5456-490f-8d9e-476a4be1dd3e\"}\n[2026-05-11 10:33:18] local.NOTICE: Monitoring end {\"correlation_id\":\"accf51c2-9f23-46e6-b225-198a661828b3\",\"trace_id\":\"0e5ff218-5456-490f-8d9e-476a4be1dd3e\"}\n[2026-05-11 10:33:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ee83ff3f-cb13-4c3e-89c9-3b9d5a1121da\",\"trace_id\":\"42bb740c-d4d6-4ae4-9208-656aca0b28ed\"}\n[2026-05-11 10:33:22] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ee83ff3f-cb13-4c3e-89c9-3b9d5a1121da\",\"trace_id\":\"42bb740c-d4d6-4ae4-9208-656aca0b28ed\"}\n[2026-05-11 10:33:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:26] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:26] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:26] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2ef6a8fb-1ce6-45a5-a1af-ba942d782843\",\"trace_id\":\"a6297a57-1443-4892-bb1e-59244e9fb65f\"}\n[2026-05-11 10:33:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3138b4af-7214-4df7-9c3f-aaafd5a012ad\",\"trace_id\":\"dadba1f4-af42-4319-8063-485e433702b9\"}\n[2026-05-11 10:33:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3138b4af-7214-4df7-9c3f-aaafd5a012ad\",\"trace_id\":\"dadba1f4-af42-4319-8063-485e433702b9\"}\n[2026-05-11 10:34:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"098f3374-2c1a-469b-98b3-1ff77b1b64ec\",\"trace_id\":\"330e4f70-0ca9-4c7a-bbc4-8b8939006f61\"}\n[2026-05-11 10:34:06] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"098f3374-2c1a-469b-98b3-1ff77b1b64ec\",\"trace_id\":\"330e4f70-0ca9-4c7a-bbc4-8b8939006f61\"}\n[2026-05-11 10:34:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"098f3374-2c1a-469b-98b3-1ff77b1b64ec\",\"trace_id\":\"330e4f70-0ca9-4c7a-bbc4-8b8939006f61\"}\n[2026-05-11 10:34:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5fd2648d-1ba5-4388-b14c-c57cd7ee1a7a\",\"trace_id\":\"1534e514-dbde-4964-ae1f-4163ec21def6\"}\n[2026-05-11 10:34:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5fd2648d-1ba5-4388-b14c-c57cd7ee1a7a\",\"trace_id\":\"1534e514-dbde-4964-ae1f-4163ec21def6\"}\n[2026-05-11 10:34:10] local.NOTICE: Monitoring start {\"correlation_id\":\"b8e36a3e-e2c5-42cc-a849-e27ab98e2880\",\"trace_id\":\"feddd752-d33b-4ce0-ac4d-21f1064646e5\"}\n[2026-05-11 10:34:10] local.NOTICE: Monitoring end {\"correlation_id\":\"b8e36a3e-e2c5-42cc-a849-e27ab98e2880\",\"trace_id\":\"feddd752-d33b-4ce0-ac4d-21f1064646e5\"}\n[2026-05-11 10:34:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3e7afa7f-cf30-4149-b943-0c33e3a5c7c5\",\"trace_id\":\"1389c85d-12c9-49b3-94d9-af4ecf2efb81\"}\n[2026-05-11 10:34:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3e7afa7f-cf30-4149-b943-0c33e3a5c7c5\",\"trace_id\":\"1389c85d-12c9-49b3-94d9-af4ecf2efb81\"}\n[2026-05-11 10:34:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:14] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:14] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"943f6408-c405-41cc-aff4-d9e2f3404c39\",\"trace_id\":\"fabc0ea1-0146-47df-8ce5-69b583246463\"}\n[2026-05-11 10:34:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:34:19] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:32:00, 2026-05-11 10:34:00] {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:34:20] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:32:00, 2026-05-11 10:34:00] {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:34:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ba94a1cc-384d-4ba3-b31b-9488c523bc09\",\"trace_id\":\"7beb272e-a15b-4966-a1b6-66e82b3115e3\"}\n[2026-05-11 10:35:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"72e15b11-c609-4153-bf9f-e4662059eb0e\",\"trace_id\":\"4d66b5da-2b77-4f3c-a1da-1a1c68c19c50\"}\n[2026-05-11 10:35:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"72e15b11-c609-4153-bf9f-e4662059eb0e\",\"trace_id\":\"4d66b5da-2b77-4f3c-a1da-1a1c68c19c50\"}\n[2026-05-11 10:35:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"72e15b11-c609-4153-bf9f-e4662059eb0e\",\"trace_id\":\"4d66b5da-2b77-4f3c-a1da-1a1c68c19c50\"}\n[2026-05-11 10:35:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b1ea8d2e-5708-4573-bf74-1464b7c44d08\",\"trace_id\":\"03dd2361-69c0-4740-b422-de6283642688\"}\n[2026-05-11 10:35:06] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b1ea8d2e-5708-4573-bf74-1464b7c44d08\",\"trace_id\":\"03dd2361-69c0-4740-b422-de6283642688\"}\n[2026-05-11 10:35:09] local.NOTICE: Monitoring start {\"correlation_id\":\"43feb1c1-6f6b-471f-97b2-ef3fc9ad29ab\",\"trace_id\":\"eb84abda-acdc-4735-becf-e37e580b0144\"}\n[2026-05-11 10:35:09] local.NOTICE: Monitoring end {\"correlation_id\":\"43feb1c1-6f6b-471f-97b2-ef3fc9ad29ab\",\"trace_id\":\"eb84abda-acdc-4735-becf-e37e580b0144\"}\n[2026-05-11 10:35:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ac80bb04-c088-44ae-94aa-08f301d989e5\",\"trace_id\":\"b6c276eb-6d35-4549-8885-62bb13d0fa9f\"}\n[2026-05-11 10:35:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ac80bb04-c088-44ae-94aa-08f301d989e5\",\"trace_id\":\"b6c276eb-6d35-4549-8885-62bb13d0fa9f\"}\n[2026-05-11 10:35:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ece2a63a-e8cd-499d-a4fd-fe7377dfce14\",\"trace_id\":\"1a0acab4-7ef5-426a-8a23-91a5b2388820\"}\n[2026-05-11 10:35:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8d3171b8-b09b-42d3-92df-98abf8692ebd\",\"trace_id\":\"141b26bb-770c-4730-ad66-f3a3ad84c825\"}\n[2026-05-11 10:35:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:purge-stale\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8d3171b8-b09b-42d3-92df-98abf8692ebd\",\"trace_id\":\"141b26bb-770c-4730-ad66-f3a3ad84c825\"}\n[2026-05-11 10:35:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"d7bec853-b7c7-4ac4-99bc-24b2c0f89e94\",\"trace_id\":\"9a5d8a19-7529-4ed1-b6de-2780141ed4f1\"}\n[2026-05-11 10:35:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:text-relay:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"d7bec853-b7c7-4ac4-99bc-24b2c0f89e94\",\"trace_id\":\"9a5d8a19-7529-4ed1-b6de-2780141ed4f1\"}\n[2026-05-11 10:35:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a3334550-1eb7-45ae-9923-b190499518e7\",\"trace_id\":\"6ad3fbaf-f20d-4a1d-9e47-06f0dbd4e3ad\"}\n[2026-05-11 10:35:21] local.INFO: Running pre-meeting notification command {\"correlation_id\":\"a3334550-1eb7-45ae-9923-b190499518e7\",\"trace_id\":\"6ad3fbaf-f20d-4a1d-9e47-06f0dbd4e3ad\"}\n[2026-05-11 10:35:21] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-notification\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a3334550-1eb7-45ae-9923-b190499518e7\",\"trace_id\":\"6ad3fbaf-f20d-4a1d-9e47-06f0dbd4e3ad\"}\n[2026-05-11 10:35:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:25] local.INFO: Running conference:monitor:start command for activities in (2026-05-11 10:25:00, 2026-05-11 10:30:00] {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:25] local.INFO: [conference:monitor:start] No activities found in (2026-05-11 10:25:00, 2026-05-11 10:30:00] {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:25] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:start\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"284237ae-0856-4884-ae72-c1df4d32529b\",\"trace_id\":\"08b1d108-a2dc-4379-a699-f38f520ffa67\"}\n[2026-05-11 10:35:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:28] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesEnded {\"from\":\"10:30\",\"to\":\"10:35\"} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:28] local.INFO: conference:monitor:end:Jiminny\\Console\\Commands\\Activities\\MonitorMeetingEndCommand::logActivitiesWithUnfinishedSession {\"from\":\"00:25\",\"to\":\"00:30\"} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:end\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ef5877ec-37ac-44cb-b1ce-46649cb3e1de\",\"trace_id\":\"389e7fbc-7207-4d74-b6eb-d107dc8f1043\"}\n[2026-05-11 10:35:33] local.NOTICE: Repairing HubSpot tokens start {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: Trying to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":59,\"provider\":\"hubspot\",\"refreshToken\":\"97b78f6e2cc49965c00c2492b602b02708b1392551e6b3f113fbaa48992af90b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.ERROR: Failed to refresh HubSpot token {\"account_id\":59,\"updated_at\":\"2025-10-03 09:32:05\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: Trying to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:33] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":306,\"provider\":\"hubspot\",\"refreshToken\":\"6fa6aa8cc641d131231acc3470f5c03cb3b07b2e580fb18f8acb3b1dbb72549b\",\"state\":\"full-refresh\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.ERROR: Failed to refresh HubSpot token {\"account_id\":306,\"updated_at\":\"2023-11-27 09:30:03\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.INFO: Trying to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1372,\"provider\":\"hubspot\",\"refreshToken\":\"9aa73948c761da29dce46c177cf9aee1fde483a44169ca38723f9f0597d7a8c4\",\"state\":\"full-refresh\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.ERROR: Failed to refresh HubSpot token {\"account_id\":1372,\"updated_at\":\"2025-10-02 14:47:06\",\"reason\":\"missing or invalid refresh token\",\"previous\":\"\"} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:34] local.NOTICE: Repairing HubSpot tokens end {\"total\":3,\"fixed\":0,\"failed\":3} {\"correlation_id\":\"ad0c7d20-6343-4842-a15b-1d6fad87bea2\",\"trace_id\":\"20ded735-c651-4ece-8b38-2a50b798f5ea\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"20844949-5e84-4735-b2d0-162745055e3d\",\"trace_id\":\"f673cac2-b390-421f-85c6-53b63c6d54e6\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"96255b3e-9e6c-40fa-b8c5-2ea047f63c25\",\"trace_id\":\"d1558e0d-cec5-4629-88da-c68477454a63\"}\n[2026-05-11 10:35:40] local.INFO: [HubSpot Journal Command] Starting polling service {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:40] local.INFO: [HubSpot Journal Polling] Service starting {\"memory_limit\":\"256M\",\"max_execution_time\":\"0\",\"initial_memory_mb\":60.0} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:40] local.INFO: [HubSpot Journal Polling] Acquired polling lock {\"expires_at\":\"2026-05-11T10:37:40.730010Z\"} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:bullhorn:ping\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"96255b3e-9e6c-40fa-b8c5-2ea047f63c25\",\"trace_id\":\"d1558e0d-cec5-4629-88da-c68477454a63\"}\n[2026-05-11 10:35:40] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:pre-meeting-reminder\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"20844949-5e84-4735-b2d0-162745055e3d\",\"trace_id\":\"f673cac2-b390-421f-85c6-53b63c6d54e6\"}\n[2026-05-11 10:35:41] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:46] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:35:51] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"646573be-6ee2-4c9a-895f-18cc290289ee\",\"trace_id\":\"f45ddc5e-217c-44cf-818a-8e19115ba801\"}\n[2026-05-11 10:36:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"646573be-6ee2-4c9a-895f-18cc290289ee\",\"trace_id\":\"f45ddc5e-217c-44cf-818a-8e19115ba801\"}\n[2026-05-11 10:36:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"646573be-6ee2-4c9a-895f-18cc290289ee\",\"trace_id\":\"f45ddc5e-217c-44cf-818a-8e19115ba801\"}\n[2026-05-11 10:36:06] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"45c6bc69-8367-4c77-b987-59184ca3a28f\",\"trace_id\":\"65f717ea-0fba-4a9b-991a-5997e0f8f9b0\"}\n[2026-05-11 10:36:07] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"45c6bc69-8367-4c77-b987-59184ca3a28f\",\"trace_id\":\"65f717ea-0fba-4a9b-991a-5997e0f8f9b0\"}\n[2026-05-11 10:36:09] local.NOTICE: Monitoring start {\"correlation_id\":\"a0611974-bf3b-409d-9f83-642f4abc0528\",\"trace_id\":\"f3d77eda-6e9f-4add-b728-61e6473902fc\"}\n[2026-05-11 10:36:09] local.NOTICE: Monitoring end {\"correlation_id\":\"a0611974-bf3b-409d-9f83-642f4abc0528\",\"trace_id\":\"f3d77eda-6e9f-4add-b728-61e6473902fc\"}\n[2026-05-11 10:36:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"8f7dcbae-1394-4d35-9ab4-9bd99edda2a7\",\"trace_id\":\"2d5ba640-0e5c-406f-9ec4-7b6c3f8088c0\"}\n[2026-05-11 10:36:11] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"8f7dcbae-1394-4d35-9ab4-9bd99edda2a7\",\"trace_id\":\"2d5ba640-0e5c-406f-9ec4-7b6c3f8088c0\"}\n[2026-05-11 10:36:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:12] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:12] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"e70f401f-86d5-4db4-94ca-9bbbe683439e\",\"trace_id\":\"777a2f92-36de-41db-820c-633d07b5c9c2\"}\n[2026-05-11 10:36:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:14] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:34:00, 2026-05-11 10:36:00] {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:14] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:34:00, 2026-05-11 10:36:00] {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a93dbfb4-71f0-4267-96fd-2f1b39448454\",\"trace_id\":\"8f0d7899-0db6-4a78-a1a2-2e3ffa4008af\"}\n[2026-05-11 10:36:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"2bafa5b7-2847-4162-b0e5-d7568645a4ff\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"crm:sync-hubspot-objects\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"2bafa5b7-2847-4162-b0e5-d7568645a4ff\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"usage\":24627560,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:16] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"refreshToken\":\"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86\",\"state\":\"connected\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b713b8da-2776-4938-8ee3-f0fbf55283c9\",\"trace_id\":\"1d932c6b-6fad-465f-b102-c442cd814509\"}\n[2026-05-11 10:36:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:notify-not-logged\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b713b8da-2776-4938-8ee3-f0fbf55283c9\",\"trace_id\":\"1d932c6b-6fad-465f-b102-c442cd814509\"}\n[2026-05-11 10:36:17] local.INFO: [SocialAccountService] Token refreshed {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"state\":\"connected\"} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [HubSpot] Syncing opportunities using strategy: lastModified {\"team\":2} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [Hubspot] Pagination completed {\"team_id\":2,\"endpoint\":\"https://api.hubapi.com/crm/v3/objects/deals/search\",\"total_requests\":1,\"total_records_fetched\":0,\"total_elapsed_seconds\":0.25,\"average_seconds_per_request\":0.25} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [HubSpot] Synced opportunities {\"team\":2,\"strategies\":\"lastModified\",\"sync_count\":0,\"total\":0,\"last_synced_id\":null,\"duration_ms\":277.55} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4\",\"provider\":\"hubspot\",\"status\":\"completed\",\"duration_ms\":1348.99,\"usage\":24981096,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"41ed251f-1bfe-48e7-a0ee-af683fae9f7d\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"usage\":24955832,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"33e34a7a-1c02-4f04-87ac-22c3a385e6e3\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":306,\"sociable_id\":109,\"provider_user_id\":\"11348452\",\"expires\":1701077403,\"refresh_token_expires\":null,\"provider\":\"hubspot\",\"state\":\"full-refresh\",\"auth_scope\":null,\"retry_after\":null,\"created_at\":\"2020-09-01 16:59:04\",\"updated_at\":\"2023-11-27 09:30:03\"}}} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":109,\"team_id\":29} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":29} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:17] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2b115eb-93ce-4d1b-929c-173757df8fba\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":40.17,\"usage\":24956128,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Your HubSpot account has become disconnected. Please login to Jiminny to reconnect.\"} {\"correlation_id\":\"878261f6-6741-40a3-9ef6-ae01845c2889\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"usage\":24913632,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"71e3aac5-fb66-47c5-a236-2d051ae3e319\",\"account\":null} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":256,\"team_id\":49} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":49} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"c6b9d6b0-b48d-4832-a68c-a57d60651888\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":357.18,\"usage\":24929752,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"34f0d5b7-4f9b-44d1-88b7-b6dc6fecc04c\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Starting sync {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"usage\":24890392,\"real_usage\":65011712,\"pid\":62058} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.WARNING: [HubSpot] Account not connected for user {\"userId\":\"2ac0447f-3c8c-4ce0-baeb-b63ddb76fa9b\",\"account\":null} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"hubspot\",\"crm_owner\":130,\"team_id\":42} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"hubspot\",\"team_id\":42} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:18] local.INFO: [SyncHubspotObjects] Sync finished {\"team\":\"b2d49a54-b645-4637-a7ae-a86cfce6e8e4\",\"provider\":\"hubspot\",\"status\":\"disconnected\",\"duration_ms\":36.73,\"usage\":24933336,\"real_usage\":65011712,\"pid\":62058,\"reason\":\"Social account for HubSpot cannot be found. Please login to Jiminny to connect.\"} {\"correlation_id\":\"02a27694-cce0-4ae8-a010-60283555b741\",\"trace_id\":\"e5c57864-6370-4a1f-a9d2-710cbdb9e72a\"}\n[2026-05-11 10:36:27] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:27] local.INFO: [EmailSchedule] STARTING Inbox Sync {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:28] local.INFO: [EmailSchedule] FINISHED Inbox Sync {\"host\":\"docker_lamp_1\",\"events\":2} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:28] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f3dfdd3b-8e69-4c5d-98fc-e9e19ed49a39\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":59} {\"correlation_id\":\"5b391868-ba48-4b0d-8aa8-b65842b802c5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 59 due to unauthorized access to the mailbox {\"correlation_id\":\"5b391868-ba48-4b0d-8aa8-b65842b802c5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":59} {\"correlation_id\":\"5b391868-ba48-4b0d-8aa8-b65842b802c5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync start {\"inbox_id\":212} {\"correlation_id\":\"cf7b2fe7-fb62-4202-956b-09a6784b3bc5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Inbox service] Skipping METADATA SYNC for inbox 212 due to unauthorized access to the mailbox {\"correlation_id\":\"cf7b2fe7-fb62-4202-956b-09a6784b3bc5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:30] local.INFO: [Sync Mailbox] Sync complete {\"inbox_id\":212} {\"correlation_id\":\"cf7b2fe7-fb62-4202-956b-09a6784b3bc5\",\"trace_id\":\"ab40cad7-217c-4407-9780-1e9a1e1cde56\"}\n[2026-05-11 10:36:36] local.INFO: [HubSpot Journal Polling] No data {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:36] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.WARNING: [HubSpot Journal Polling] Maximum empty results reached, stopping {\"empty_results\":5,\"max_empty_results\":5} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.INFO: [HubSpot Journal Polling] Service ending {\"runtime_seconds\":57,\"total_cycles\":5,\"files_downloaded\":0,\"empty_files\":0,\"other_portal_skipped\":0,\"total_events\":0,\"events_per_file\":0,\"avg_api_ms\":190.5,\"avg_download_ms\":0.0,\"avg_transform_ms\":0.0,\"avg_process_ms\":0.0,\"peak_memory_mb\":99.73} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.INFO: [HubSpot Journal Polling] Saved offset to database on cleanup {\"offset\":\"019e15a9-9ea0-7da7-87bc-82592e3ccf0d\"} {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:36:37] local.INFO: [HubSpot Journal Polling] Released polling lock {\"correlation_id\":\"c4abe253-3d14-49bf-bc79-afa71ccd4174\",\"trace_id\":\"305a578b-df45-4c12-b1c2-16e62f3fa6fa\"}\n[2026-05-11 10:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a6bf12a7-3d44-4661-9fec-f5ab6d89bcf6\",\"trace_id\":\"f56da488-8a51-443c-a69b-799615697e25\"}\n[2026-05-11 10:37:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"a6bf12a7-3d44-4661-9fec-f5ab6d89bcf6\",\"trace_id\":\"f56da488-8a51-443c-a69b-799615697e25\"}\n[2026-05-11 10:37:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a6bf12a7-3d44-4661-9fec-f5ab6d89bcf6\",\"trace_id\":\"f56da488-8a51-443c-a69b-799615697e25\"}\n[2026-05-11 10:37:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"c831237f-7638-4919-b5a1-785d5aaeee99\",\"trace_id\":\"11fac131-feb0-443c-ba9f-e5215a104d04\"}\n[2026-05-11 10:37:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"c831237f-7638-4919-b5a1-785d5aaeee99\",\"trace_id\":\"11fac131-feb0-443c-ba9f-e5215a104d04\"}\n[2026-05-11 10:37:10] local.NOTICE: Monitoring start {\"correlation_id\":\"3285ad9f-3fed-491c-a8dc-3737343e83ea\",\"trace_id\":\"77a84391-a532-4d0a-9847-b862f29ddd75\"}\n[2026-05-11 10:37:10] local.NOTICE: Monitoring end {\"correlation_id\":\"3285ad9f-3fed-491c-a8dc-3737343e83ea\",\"trace_id\":\"77a84391-a532-4d0a-9847-b862f29ddd75\"}\n[2026-05-11 10:37:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fbd5efb3-e8a5-4e05-a201-40e67d8c5d57\",\"trace_id\":\"9aebad16-8ed6-4d38-bcd5-04f2875cbde3\"}\n[2026-05-11 10:37:12] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fbd5efb3-e8a5-4e05-a201-40e67d8c5d57\",\"trace_id\":\"9aebad16-8ed6-4d38-bcd5-04f2875cbde3\"}\n[2026-05-11 10:37:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:14] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:14] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ddda85cf-aa7c-46af-8f89-3933e04a14e2\",\"trace_id\":\"a96c0f85-f44a-43df-9bf8-bf99a4f393a8\"}\n[2026-05-11 10:37:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:16] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:16] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b5fdb1a7-bede-46f6-9916-4ef25c6f8d4a\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:18] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"a939b046-9e38-485d-afb9-a17b4b7907f4\",\"trace_id\":\"286955ea-f882-4728-9ff7-befacbc6b77a\"}\n[2026-05-11 10:37:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"70310051-3a12-46e9-84a4-89c72f743167\",\"trace_id\":\"a37be552-6047-475b-951a-06ff4a9507f5\"}\n[2026-05-11 10:37:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"70310051-3a12-46e9-84a4-89c72f743167\",\"trace_id\":\"a37be552-6047-475b-951a-06ff4a9507f5\"}\n[2026-05-11 10:38:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"46b097b8-0b96-4d90-8a93-539a384c5823\",\"trace_id\":\"74d4d667-dc86-448e-a692-45ff5cb453cd\"}\n[2026-05-11 10:38:04] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"46b097b8-0b96-4d90-8a93-539a384c5823\",\"trace_id\":\"74d4d667-dc86-448e-a692-45ff5cb453cd\"}\n[2026-05-11 10:38:04] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"46b097b8-0b96-4d90-8a93-539a384c5823\",\"trace_id\":\"74d4d667-dc86-448e-a692-45ff5cb453cd\"}\n[2026-05-11 10:38:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"3a67375e-c351-4ae5-82bc-948e778e0048\",\"trace_id\":\"d2248abd-029a-44e7-9157-58a0622bfc10\"}\n[2026-05-11 10:38:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"3a67375e-c351-4ae5-82bc-948e778e0048\",\"trace_id\":\"d2248abd-029a-44e7-9157-58a0622bfc10\"}\n[2026-05-11 10:38:11] local.NOTICE: Monitoring start {\"correlation_id\":\"036a52a0-2c7b-4b54-a54d-01900cc57738\",\"trace_id\":\"aa5f7049-6f54-4d09-a774-be41c55079b6\"}\n[2026-05-11 10:38:11] local.NOTICE: Monitoring end {\"correlation_id\":\"036a52a0-2c7b-4b54-a54d-01900cc57738\",\"trace_id\":\"aa5f7049-6f54-4d09-a774-be41c55079b6\"}\n[2026-05-11 10:38:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"ac59669b-fbbb-4d3c-975b-b48d7e219deb\",\"trace_id\":\"ac455aaf-2475-4e43-8532-720d4707b298\"}\n[2026-05-11 10:38:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"ac59669b-fbbb-4d3c-975b-b48d7e219deb\",\"trace_id\":\"ac455aaf-2475-4e43-8532-720d4707b298\"}\n[2026-05-11 10:38:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:15] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:15] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:15] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"a60bf9cd-58a0-4685-9951-85c5bee9ba48\",\"trace_id\":\"b9d41bb4-11e8-4df5-92cc-79e4ad2b5706\"}\n[2026-05-11 10:38:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:18] local.INFO: Running conference:monitor:count command for activities in (2026-05-11 10:36:00, 2026-05-11 10:38:00] {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:18] local.INFO: [conference:monitor:count] No activities found in (2026-05-11 10:36:00, 2026-05-11 10:38:00] {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:18] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"1915f24d-f846-4713-8a4c-68b28b5c7d10\",\"trace_id\":\"6e5d441d-34f0-4450-a7c6-a621eb68b6ab\"}\n[2026-05-11 10:38:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fef6e1aa-1b8b-46da-b451-cf6ab0fc7698\",\"trace_id\":\"e8a43881-fcaf-40af-80b9-afe0bbcbaac1\"}\n[2026-05-11 10:38:20] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:retry-failed\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fef6e1aa-1b8b-46da-b451-cf6ab0fc7698\",\"trace_id\":\"e8a43881-fcaf-40af-80b9-afe0bbcbaac1\"}\n[2026-05-11 10:39:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"f6f145bd-ff6f-43b8-9428-a1dfacda358f\",\"trace_id\":\"82b82fdf-25bf-445c-a495-961fb5037236\"}\n[2026-05-11 10:39:05] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"f6f145bd-ff6f-43b8-9428-a1dfacda358f\",\"trace_id\":\"82b82fdf-25bf-445c-a495-961fb5037236\"}\n[2026-05-11 10:39:05] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"f6f145bd-ff6f-43b8-9428-a1dfacda358f\",\"trace_id\":\"82b82fdf-25bf-445c-a495-961fb5037236\"}\n[2026-05-11 10:39:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"61cd5d9f-ca83-40ba-bcf1-828523d60cd9\",\"trace_id\":\"b713000b-147e-48f1-887e-f230ec0cb18a\"}\n[2026-05-11 10:39:08] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"61cd5d9f-ca83-40ba-bcf1-828523d60cd9\",\"trace_id\":\"b713000b-147e-48f1-887e-f230ec0cb18a\"}\n[2026-05-11 10:39:11] local.NOTICE: Monitoring start {\"correlation_id\":\"30a5fa99-8b11-4637-a67e-25437db0dec1\",\"trace_id\":\"b92ae3ad-cbf2-4323-9146-cea7de2e9b0b\"}\n[2026-05-11 10:39:11] local.NOTICE: Monitoring end {\"correlation_id\":\"30a5fa99-8b11-4637-a67e-25437db0dec1\",\"trace_id\":\"b92ae3ad-cbf2-4323-9146-cea7de2e9b0b\"}\n[2026-05-11 10:39:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"40697c1c-e78d-4166-991a-23dee13df5ac\",\"trace_id\":\"7adaa4f7-a908-4fbc-b2a9-497c6f2c8f73\"}\n[2026-05-11 10:39:14] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"40697c1c-e78d-4166-991a-23dee13df5ac\",\"trace_id\":\"7adaa4f7-a908-4fbc-b2a9-497c6f2c8f73\"}\n[2026-05-11 10:39:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:16] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:16] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:16] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"0206193a-843d-475b-b473-c190a6d13030\",\"trace_id\":\"de3102cb-294e-475d-a78d-18da674a3f01\"}\n[2026-05-11 10:39:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: [SocialAccountService] Token retrieved {\"socialAccountId\":1496,\"provider\":\"aircall\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.ERROR: [Aircall] Re-activating webhooks failed {\"team_id\":1,\"reason\":\"{\\\"message\\\":\\\"Forbidden\\\"}\"} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:19] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:aircall:check-and-renew\",\"memoryBeforeCommandInMb\":60.0,\"memoryAfterCommandInMB\":60.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"5ff2e854-cab6-47d7-a286-72cb7d73404f\",\"trace_id\":\"2cf94980-8fdf-4ef8-b1f6-ffb15c7546f0\"}\n[2026-05-11 10:39:22] local.INFO: [RetryFailedDownloads] Starting {\"options\":{\"from\":null,\"to\":null,\"help\":false,\"silent\":false,\"quiet\":false,\"verbose\":false,\"version\":false,\"ansi\":null,\"no-interaction\":false,\"env\":null}} {\"correlation_id\":\"0090d89b-5dff-472f-a7db-3bffabdf1eb7\",\"trace_id\":\"3c2e9b6b-2e7f-4460-9aa8-e287cdb20dfe\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2182346632676777962
|
3295662306969729399
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Reader Mode
<?php
namespace SevenShores\Hubspot\Exceptions;
class BadRequest extends HubspotException
{
}
Show Replace Field
Search History
Received 429 from API
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/5
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
342
Previous Highlighted Error
Next Highlighted Error
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":615092,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":615092} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":615092,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [MatchActivityCrmData] Participants old state {"activity":615092,"participants":[{"id":1004102,"user_id":null,"contact_id":null,"lead_id":null},{"id":1004103,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] Cache miss, calling the API {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Hubspot] Failed to fetch contact {"email":"[EMAIL]","reason":"[404] Client error: `GET https://api.hubapi.com/crm/v3/objects/contacts/nikolay.nikolov%40jiminny.com?properties=email%2Cfirstname%2Clastname%2Ccountry%2Cphone%2Cmobilephone%2Cjobtitle%2Chubspot_owner_id%2Cassociatedcompanyid%2Cphoto&archived=0&idProperty=email` resulted in a `404 Not Found` response"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:03] local.INFO: [Prospect match] API returned empty result, caching the miss with empty prospect data {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] No retry-after header or policy name found, using default {"exception_class":"SevenShores\\Hubspot\\Exceptions\\BadRequest"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.WARNING: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"policy":null,"reason":"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:
{\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT\",\"correlationId\":\"019e168a-5 (truncated...)
"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614436,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614436} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614436,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614436,"participants":[{"id":1002751,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002752,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":14} {"correlation_id":"858d73b2-b1ef-46ae-ba14-6ba5fb5e53ab","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614382,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614382} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614382,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614382,"participants":[{"id":1002632,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002633,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"78f847cf-6495-4054-b3d4-e179a133bd42","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614381,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":null,"account_id":26,"opportunity_id":22,"stage_id":89}} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614381} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614381,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614381,"participants":[{"id":1002630,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002631,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":11} {"correlation_id":"97d1197e-aa94-42ee-80b1-9cc6d9e96a9b","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":614378,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":6167,"account_id":null,"opportunity_id":null,"stage_id":null}} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":614378} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":614378,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":614378,"participants":[{"id":1002623,"user_id":null,"contact_id":null,"lead_id":null},{"id":1002624,"user_id":null,"contact_id":6167,"lead_id":null},{"id":1002625,"user_id":89,"contact_id":null,"lead_id":null}]} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] cached empty result - no API calls, try next matching method {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [HandleHubspotRateLimit] Rate limit caught, releasing job with delay {"job_class":"Jiminny\\Jobs\\Crm\\MatchActivityCrmData","attempts":1,"retry_after":10,"delay":15} {"correlation_id":"2522b1c9-7751-4eb5-874a-0cacc3cf2ac5","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613840,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613840} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613840,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613840,"participants":[{"id":1001764,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001765,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: ProspectCache - Searching DB for opportunity by owner {"account_id":244,"contact_id":4487,"owner_id":261} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: ProspectCache - Opportunity DB search results {"account_id":244,"contact_id":4487,"opportunity_id":299} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613840,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613840,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613840} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613840,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613840,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"14d1f2d6-526c-4a7b-9dbe-f310d28baff2","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613833,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613833} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613833,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613833,"participants":[{"id":1001750,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001751,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613833,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613833,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613833} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613833,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613833,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"f9846f48-5841-4a71-b500-64b802c67d05","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613827,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613827} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613827,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613827,"participants":[{"id":1001734,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001735,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613827,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613827,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613827} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613827,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613827,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"d060f13a-e3b7-416c-ac24-ebc305d1fd66","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613826,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613826} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613826,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613826,"participants":[{"id":1001732,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001733,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613826,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613826,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613826} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613826,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613826,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"b3cb7cc8-9e53-4962-af9d-a06a2bc1211f","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613820,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613820} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613820,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613820,"participants":[{"id":1001721,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001722,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613820,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613820,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613820} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613820,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613820,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"ee78448a-70af-4da3-a3cd-238e2067a49c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613818,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613818} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613818,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613818,"participants":[{"id":1001717,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001718,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613818,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613818,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613818} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:04] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613818,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613818,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"74704a29-86b2-4b3f-ae73-0e6d4ec1891a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613812,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36}} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613812} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613812,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613812,"participants":[{"id":1001705,"user_id":null,"contact_id":4487,"lead_id":null},{"id":1001706,"user_id":261,"contact_id":null,"lead_id":null}]} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613812,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613812,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613812} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613812,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613812,"remote_search":true,"lead_id":null,"contact_id":4487,"account_id":244,"opportunity_id":299,"stage_id":36} {"correlation_id":"0698152e-ea7b-46d1-95e4-45730b1aac4c","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Starting CRM data matching {"activity":613807,"remote_search":true,"set_configuration":2,"old_state":{"lead_id":null,"contact_id":4484,"account_id":243,"opportunity_id":276,"stage_id":36}} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613807} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613807,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Participants old state {"activity":613807,"participants":[{"id":1001690,"user_id":253,"contact_id":null,"lead_id":null},{"id":1001691,"user_id":null,"contact_id":4484,"lead_id":null}]} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [SocialAccountService] Token retrieved {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] Email domain belongs to the team, skipping crm lookup {"activity_id":613807,"team_id":2,"email":"[EMAIL]"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: ProspectCache - Searching DB for opportunity by owner {"account_id":243,"contact_id":4484,"owner_id":253} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: ProspectCache - Fallback DB opportunity search {"account_id":243,"contact_id":4484} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: ProspectCache - Opportunity DB search results {"account_id":243,"contact_id":4484,"opportunity_id":276} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [Prospect match] Cache / local search hit {"identifier_type":"email","identifier":"[EMAIL]"} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [CrmActivityService] CRM matching completed {"activity_id":613807,"participants_processed":2,"exact_matches":1,"domain_matches":0,"best_match_found":true} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ EsUpdateTarget ] Update single target {"target":"activities","purpose":"searchable-observer-update","entityId":613807} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [ AsyncUpdateElasticSearch ] Entity added to Redis list {"entityType":"activities","entityId":613807,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"503e9564-ad58-44d0-9757-576b830ee22a","trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}
[2026-05-11 10:17:05] local.INFO: [MatchActivityCrmData] Successfully matched CRM data {"activity":613807,"remote_search"...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17889
|
780
|
24
|
2026-05-11T10:40:08.387809+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496008387_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"68","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Reacts to a rate limits (429) from HubSpot by translating it\n * into a RateLimitException carrying retry_after.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedRetryAfter = Redis::get($cacheKey);\n if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n (int) $cachedRetryAfter,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'policy' => $this->parsePolicy($e),\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));\n return 5;\n\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $policy = $this->parsePolicy($e);\n if ($policy === 'TEN_SECONDLY_ROLLING') {\n return 10;\n }\n if ($policy === 'SECONDLY') {\n return 1;\n }\n if ($policy === 'DAILY_LIMIT') {\n return 600;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function parsePolicy(Throwable $e): ?string\n {\n if (! method_exists($e, 'getResponseBody')) {\n return null;\n }\n\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n\n if (! is_array($body)) {\n return null;\n }\n\n $policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;\n\n return is_string($policy) ? strtoupper($policy) : null;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n// } catch (RateLimitException $e) {\n// throw $e;\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2034405513842901713
|
5225837844252985444
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
68
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedRetryAfter = Redis::get($cacheKey);
if (is_string($cachedRetryAfter) && is_numeric($cachedRetryAfter)) {
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
(int) $cachedRetryAfter,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
Redis::setex($cacheKey, $retryAfter, (string) $retryAfter);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'policy' => $this->parsePolicy($e),
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$e ' . PHP_EOL . print_r($e, true));
return 5;
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$policy = $this->parsePolicy($e);
if ($policy === 'TEN_SECONDLY_ROLLING') {
return 10;
}
if ($policy === 'SECONDLY') {
return 1;
}
if ($policy === 'DAILY_LIMIT') {
return 600;
}
$this->log->warning('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function parsePolicy(Throwable $e): ?string
{
if (! method_exists($e, 'getResponseBody')) {
return null;
}
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
if (! is_array($body)) {
return null;
}
$policy = $body['policyName'] ?? $body['policy'] ?? $body['context']['policyName'] ?? null;
return is_string($policy) ? strtoupper($policy) : null;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
// } catch (RateLimitException $e) {
// throw $e;
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17890
|
781
|
21
|
2026-05-11T10:40:08.163841+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778496008163_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.09541223,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.82413566,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8394282,"top":0.019952115,"width":0.076130316,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7523250959739836127
|
-8890102039368849016
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-limiProiect© BatchSyncCollectolsynckelatedAcuvnymanager.ong(C) CachedCrmServiceDecorator.onp© ProspectCache.phpe balchsynckealssec clientone© ClosedDealStagesS © RateLimitException.phDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phrclass Cllent extends Baseclient 1mpLements HubspotcllentintertaceC) FieldT vpeconvertee Hubspotclientinterc) Hubspotlokenman© PayloadBuilder.phpC) RemotecrmobiectP ResponseNormalizec) Service.onrC)SvncFieldAction.onC) SvncRelatedActivitC) WebhookSvncBatclv MintearationAorM Acceccors• D ConfigD DTO• M SiltersD Jobs• M ProcnectSoarchStreW sevice lraits© DataClient.php© DecorateActivity.ph135(e)LocalSearch.onpu LocalSearchintertac© RemoteSearch.php137138c) Service.php140v W Listeners© ConvertLeadActivitc) PurceLookuocachel> M Metadata> Miarationi> = Pioedrivev Salesforce• D FieldsM OnnortunitvMatcheMOnnortunitvSvneSt149|M ProsneetSearchStr.• M ServiceTraitcC) Client nhr© DecorateActivity.ph. Delete@biectsTrait© FieldDefinitions.php© PayloadBuilder.php© Profile.php© QueryBuilder.php15515Spublic tunction 1sHubspotRateL1m1tThrowable se: boouif (Se instanceof BadReauestse instanceor DealaotExceotionI1 $e instanceof ContactApiExceptionSe instanceof ComoanuAni Excention11 $e instanceofGuzzleltto Excention ReauestExcentionireturn Gint Se->aetCode0 z== 429%neturn false.1 usagepublic function parseRetryAfter(Throwable $e): intl\Illuminate\Support\Facades\Log::channel( channel: 'custom_channel')->info('$e' . PHP_EOL . print_r($e, return: true))return 5:if (method exists(Se.method: 'getResponseHeaders')) {Sheaders = $e->qetResponseHeadersO ?: [1:Svalue = Sheaders['Retry-After'] ?? Sheaders['retry-after'] ?? null:if (is array(Svalue)) {Svalue = $valuel0l 22 null:if (is numeric(Svalue)) {return (int) Svalue:Snoliev = sthis->nansePolli.ev(se):14 Snolbiev ===ITEN SECONOLY ROLLING')neturn 10.if (Spolicy === 'SECONDLY') {neturn 1•if (Spolicy === 'DAILY_LIMIT') {notunn kad.Sthis->log->warning('[Hubspotl No retry-after header or policy name found, using default'. r'exception class' => qet class(Se).•veryacuviycmmlaskJoo.ongM| A3 A68 X3 A VI IMII TII MШ11Tects naccod. 12 127 msuppont Dally • In 1h z0m100% 1Mon 11 May 13:40:08Received 429 from APICc W.*emote_search": true, "set_configuration":2,"old_state":?"Lead_id":null, "contact_id":null, "account_id":26, "opportunity_id":22,"stage_id":895 tactivities","entityId":615092,"collectionKey":"activities-for-update-priority","withPriority":true} {"correlation_id":"f0becb3b-1f4f-4fb3-a31contact id".null "lead id".nulle? "con"identifier":"[EMAIL]"} {"correlation_id":"f0becb3b-1f4f-4fb3-a311-9056fd2ae449","trace_id":"8e45b868-2eb5-42f8-a91e-229#noacon"."rhazl Client ennoprospect data {"identifienСудес епать, поепешевс пикоцау.лико сомодшалпу, сош з сомеlастов дас торесоро-итат-чтоз-азл-У050т02ае44Yter":10, "policy":null,"reason":"Client error:rusi necos:/ap1.nubapz.com/crm/vs/00zecrs/concact/ searchresulced in a 42y 100 Many kequest"correlationId) ":"019e168a-5 (truncated...)57d"iob class"."Jiminnv| \Jobs|\Crm| \MatchActivitvCrmData" "attempts":1, "retry aften":10."delav":14} {"correlation_id"."f0becb3b-1f4f-4fb3-a311-90emote search":true, "set configuration":2."old state".{"lead_id":null, "contact_ id":null, "account_id":26."opportunity id":22 "stage_id":89}} {""withPriority":true- «"correlation_1d":"85807502-b1ef-46ae-bar:89. "contact id":null. "lead_id":null}l} {"conmethod {"identifier_type":"ioh class"."Jiminnv lobs Crm MatchActivitvCrmData" "attemots".1 "retry aften".10. "delavcontact idi.null "lead idi.oullli suconrrelation_id":"78f847cf-6495-4054-b3d4-e179a133bd42" "trace_id":"8e45b868-2eb5-42f8-a91e-22951e49d57d"}dentifier":"nikolay.nikolov@jiminnymothod Siidontifion tunoll.llomaiiiiob_class"."Jiminny) \Jobs|\Crm| \MatchActivityCrmDat:cipants": [{"id":1002"opportunity id":22."staqe_id":89}} {'"trace_1d":"8e450868-2eb5-42f8-a9method"identifier...
|
17888
|
NULL
|
NULL
|
NULL
|