ملخص
واجهة برمجة تطبيقات HubSpot تتيح للمطورين تكاملًا فعالًا مع أنظمة إدارة علاقات العملاء (CRM) وأدوات التسويق والمبيعات والخدمة. تعتمد على مصادقة OAuth 2.0 أو التطبيقات الخاصة وتوفر نقاط نهاية RESTful لإدارة جهات الاتصال والشركات والصفقات والتذاكر وغيرها. ستتعلم في هذا الدليل كيفية إعداد المصادقة، استخدام أهم نقاط النهاية، تكوين Webhooks، وتنفيذ التكاملات البرمجية للإنتاج.
مقدمة
تدير HubSpot أكثر من 194,000 حساب و مليارات سجلات CRM. إذا كنت مطورًا تسعى لبناء تكاملات CRM أو أتمتة التسويق أو أدوات المبيعات، فإن استخدام API HubSpot أمر ضروري للوصول إلى ملايين المستخدمين.
الحقيقة أن الشركات تهدر 15-20 ساعة أسبوعيًا في إدخال البيانات يدويًا. تكامل قوي مع API HubSpot يمكّنك من أتمتة مزامنة جهات الاتصال، تحديثات الصفقات، سير عمل التسويق، والتقارير بين الأنظمة.
💡يُبسّط Apidog اختبار تكامل API. اختبر نقاط نهاية HubSpot الخاصة بك، وتحقق من تدفقات OAuth، وافحص حمولات webhook، وقم بتصحيح أخطاء المصادقة في مساحة عمل واحدة. قم باستيراد مواصفات API، ومحاكاة الاستجابات، ومشاركة سيناريوهات الاختبار مع فريقك.
ما هي واجهة برمجة تطبيقات HubSpot؟
توفر HubSpot API (RESTful) للوصول إلى بيانات CRM وأتمتة التسويق، وتشمل:
- جهات الاتصال، الشركات، الصفقات، التذاكر، والكائنات المخصصة
- رسائل البريد الإلكتروني التسويقية والصفحات المقصودة
- عمليات ومسارات المبيعات
- تذاكر الخدمة والمحادثات
- التحليلات والتقارير
- سير العمل والأتمتة
- الملفات والأصول
الميزات الرئيسية
| الميزة | الوصف |
|---|---|
| تصميم RESTful | طرق HTTP قياسية مع استجابات JSON |
| OAuth 2.0 + تطبيقات خاصة | خيارات مصادقة مرنة |
| Webhooks | إشعارات في الوقت الفعلي لتغييرات الكائنات |
| تحديد المعدل | حدود قائمة على المستوى (100-400 طلب/ثانية) |
| كائنات CRM | دعم الكائنات القياسية والمخصصة |
| الروابط | ربط الكائنات ببعضها (جهة اتصال-شركة، صفقة-جهة اتصال) |
| الخصائص | حقول مخصصة لأي نوع كائن |
| واجهة برمجة تطبيقات البحث | تصفية وفرز معقدان |
نظرة عامة على بنية API
تعتمد HubSpot على واجهات REST مع إصدار:
https://api.hubapi.com/
مقارنة إصدارات API
| الإصدار | الحالة | المصادقة | حالة الاستخدام |
|---|---|---|---|
| CRM API v3 | حالي | OAuth 2.0، تطبيق خاص | جميع التكاملات الجديدة |
| Automation API v4 | حالي | OAuth 2.0، تطبيق خاص | تسجيل سير العمل |
| Marketing Email API | حالي | OAuth 2.0، تطبيق خاص | حملات البريد الإلكتروني |
| Contacts API v1 | مهمل | مفتاح API (قديم) | الترحيل إلى الإصدار 3 |
| Companies API v1 | مهمل | مفتاح API (قديم) | الترحيل إلى الإصدار 3 |
هام: تم إهمال مصادقة مفتاح API لصالح OAuth 2.0 والتطبيقات الخاصة. يجب ترحيل جميع التكاملات فورًا.
البدء: إعداد المصادقة
الخطوة 1: إنشاء حساب مطور HubSpot
- ادخل إلى بوابة مطوري HubSpot
- سجل الدخول أو أنشئ حسابًا جديدًا
- انتقل إلى التطبيقات في لوحة التحكم
- اضغط إنشاء تطبيق
الخطوة 2: اختيار طريقة المصادقة
| الطريقة | الأفضل لـ | مستوى الأمان |
|---|---|---|
| OAuth 2.0 | تطبيقات متعددة المستأجرين، تكاملات عامة | مرتفع (رموز مميزة محددة للمستخدم) |
| تطبيق خاص | تكاملات داخلية، بوابة واحدة | مرتفع (رمز مميز محدد للبوابة) |
الخطوة 3: إعداد تطبيق خاص (للتكاملات الداخلية)
قم بإنشاء تطبيق خاص للوصول إلى بوابة واحدة:
- الإعدادات > التكاملات > التطبيقات الخاصة
- اضغط إنشاء تطبيق خاص
- حدد الصلاحيات المطلوبة (Scopes):
contacts
crm.objects.companies
crm.objects.deals
crm.objects.tickets
automation
webhooks
- أنشئ رمز الوصول واحتفظ به في ملف آمن:
# .env file
HUBSPOT_ACCESS_TOKEN="pat-na1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
HUBSPOT_PORTAL_ID="12345678"
الخطوة 4: إعداد OAuth 2.0 (للتطبيقات متعددة المستأجرين)
- التطبيقات > إنشاء تطبيق
- إعداد بيانات المصادقة:
const HUBSPOT_CLIENT_ID = process.env.HUBSPOT_CLIENT_ID;
const HUBSPOT_CLIENT_SECRET = process.env.HUBSPOT_CLIENT_SECRET;
const HUBSPOT_REDIRECT_URI = process.env.HUBSPOT_REDIRECT_URI;
// بناء رابط التفويض
const getAuthUrl = (state) => {
const params = new URLSearchParams({
client_id: HUBSPOT_CLIENT_ID,
redirect_uri: HUBSPOT_REDIRECT_URI,
scope: 'crm.objects.contacts.read crm.objects.contacts.write',
state: state,
optional_scope: 'crm.objects.deals.read'
});
return `https://app.hubspot.com/oauth/authorize?${params.toString()}`;
};
الخطوة 5: تبادل رمز التفويض برمز وصول
const exchangeCodeForToken = async (code) => {
const response = await fetch('https://api.hubspot.com/oauth/v1/token', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: HUBSPOT_CLIENT_ID,
client_secret: HUBSPOT_CLIENT_SECRET,
redirect_uri: HUBSPOT_REDIRECT_URI,
code: code
})
});
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
portalId: data.hub_portal_id
};
};
// التعامل مع رد النداء
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
try {
const tokens = await exchangeCodeForToken(code);
// تخزين الرموز
await db.installations.create({
portalId: tokens.portalId,
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
tokenExpiry: Date.now() + (tokens.expiresIn * 1000)
});
res.redirect('/success');
} catch (error) {
console.error('OAuth error:', error);
res.status(500).send('Authentication failed');
}
});
الخطوة 6: تحديث رمز الوصول
const refreshAccessToken = async (refreshToken) => {
const response = await fetch('https://api.hubspot.com/oauth/v1/token', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
grant_type: 'refresh_token',
client_id: HUBSPOT_CLIENT_ID,
client_secret: HUBSPOT_CLIENT_SECRET,
refresh_token: refreshToken
})
});
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in
};
};
// تحقق تلقائي من صلاحية الرمز
const ensureValidToken = async (portalId) => {
const installation = await db.installations.findByPortalId(portalId);
// تحديث إذا قارب الانتهاء
if (installation.tokenExpiry < Date.now() + 1800000) {
const newTokens = await refreshAccessToken(installation.refreshToken);
await db.installations.update(installation.id, {
accessToken: newTokens.accessToken,
refreshToken: newTokens.refreshToken,
tokenExpiry: Date.now() + (newTokens.expiresIn * 1000)
});
return newTokens.accessToken;
}
return installation.accessToken;
};
الخطوة 7: إجراء مكالمات API المصادق عليها
const HUBSPOT_BASE_URL = 'https://api.hubapi.com';
const hubspotRequest = async (endpoint, options = {}, portalId = null) => {
const accessToken = portalId ? await ensureValidToken(portalId) : process.env.HUBSPOT_ACCESS_TOKEN;
const response = await fetch(`${HUBSPOT_BASE_URL}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`HubSpot API Error: ${error.message}`);
}
return response.json();
};
// استخدام
const contacts = await hubspotRequest('/crm/v3/objects/contacts');
العمل مع كائنات CRM
إنشاء جهة اتصال
const createContact = async (contactData) => {
const contact = {
properties: {
email: contactData.email,
firstname: contactData.firstName,
lastname: contactData.lastName,
phone: contactData.phone,
company: contactData.company,
website: contactData.website,
lifecyclestage: contactData.lifecycleStage || 'lead'
}
};
const response = await hubspotRequest('/crm/v3/objects/contacts', {
method: 'POST',
body: JSON.stringify(contact)
});
return response;
};
// مثال عملي
const contact = await createContact({
email: 'john.doe@example.com',
firstName: 'John',
lastName: 'Doe',
phone: '+1-555-0123',
company: 'Acme Corp',
lifecycleStage: 'customer'
});
console.log(`Contact created: ${contact.id}`);
خصائص جهة الاتصال
| الخاصية | النوع | الوصف |
|---|---|---|
email |
نص (String) | البريد الإلكتروني الأساسي (معرّف فريد) |
firstname |
نص (String) | الاسم الأول |
lastname |
نص (String) | الاسم الأخير |
phone |
نص (String) | رقم الهاتف |
company |
نص (String) | اسم الشركة |
website |
نص (String) | عنوان URL للموقع الإلكتروني |
lifecyclestage |
تعداد (Enum) | عميل محتمل، عميل محتمل مؤهل تسويقيًا، عميل محتمل مؤهل مبيعاتيًا، فرصة، عميل، مبشر، مشترك |
createdate |
تاريخ ووقت (DateTime) | يتم إنشاؤه تلقائيًا |
lastmodifieddate |
تاريخ ووقت (DateTime) | يتم إنشاؤه تلقائيًا |
الحصول على جهة اتصال
const getContact = async (contactId) => {
const response = await hubspotRequest(`/crm/v3/objects/contacts/${contactId}`);
return response;
};
// مثال عملي
const contact = await getContact('12345');
console.log(`${contact.properties.firstname} ${contact.properties.lastname}`);
console.log(`Email: ${contact.properties.email}`);
البحث عن جهات الاتصال
const searchContacts = async (searchCriteria) => {
const response = await hubspotRequest('/crm/v3/objects/contacts/search', {
method: 'POST',
body: JSON.stringify({
filterGroups: searchCriteria,
properties: ['firstname', 'lastname', 'email', 'company'],
limit: 100
})
});
return response;
};
// البحث عن جميع جهات الاتصال في شركة معينة
const results = await searchContacts({
filterGroups: [
{
filters: [
{
propertyName: 'company',
operator: 'EQ',
value: 'Acme Corp'
}
]
}
]
});
results.results.forEach(contact => {
console.log(`${contact.properties.email}`);
});
عوامل تشغيل تصفية البحث
| العامل | الوصف | مثال |
|---|---|---|
EQ |
يساوي | company EQ 'Acme' |
NEQ |
لا يساوي | lifecyclestage NEQ 'subscriber' |
CONTAINS_TOKEN |
يحتوي على | email CONTAINS_TOKEN 'gmail' |
NOT_CONTAINS_TOKEN |
لا يحتوي على | email NOT_CONTAINS_TOKEN 'test' |
GT |
أكبر من | createdate GT '2026-01-01' |
LT |
أقل من | createdate LT '2026-12-31' |
GTE |
أكبر من أو يساوي | deal_amount GTE 10000 |
LTE |
أقل من أو يساوي | deal_amount LTE 50000 |
HAS_PROPERTY |
يحتوي على قيمة | phone HAS_PROPERTY |
NOT_HAS_PROPERTY |
قيمة مفقودة | phone NOT_HAS_PROPERTY |
إنشاء شركة
const createCompany = async (companyData) => {
const company = {
properties: {
name: companyData.name,
domain: companyData.domain,
industry: companyData.industry,
numberofemployees: companyData.employees,
annualrevenue: companyData.revenue,
city: companyData.city,
state: companyData.state,
country: companyData.country
}
};
const response = await hubspotRequest('/crm/v3/objects/companies', {
method: 'POST',
body: JSON.stringify(company)
});
return response;
};
// مثال عملي
const company = await createCompany({
name: 'Acme Corporation',
domain: 'acme.com',
industry: 'Technology',
employees: 500,
revenue: 50000000,
city: 'San Francisco',
state: 'CA',
country: 'USA'
});
ربط الكائنات
const associateContactWithCompany = async (contactId, companyId) => {
const response = await hubspotRequest(
`/crm/v3/objects/contacts/${contactId}/associations/companies/${companyId}`,
{
method: 'PUT',
body: JSON.stringify({
types: [
{
associationCategory: 'HUBSPOT_DEFINED',
associationTypeId: 1 // Contact to Company
}
]
})
}
);
return response;
};
// مثال عملي
await associateContactWithCompany('12345', '67890');
أنواع الروابط
| الرابط | معرّف النوع | الاتجاه |
|---|---|---|
| جهة اتصال → شركة | 1 | جهة الاتصال مرتبطة بالشركة |
| شركة → جهة اتصال | 1 | الشركة لديها جهة اتصال مرتبطة |
| صفقة → جهة اتصال | 3 | الصفقة مرتبطة بجهة اتصال |
| صفقة → شركة | 5 | الصفقة مرتبطة بالشركة |
| تذكرة → جهة اتصال | 16 | التذكرة مرتبطة بجهة اتصال |
| تذكرة → شركة | 15 | التذكرة مرتبطة بالشركة |
إنشاء صفقة
const createDeal = async (dealData) => {
const deal = {
properties: {
dealname: dealData.name,
amount: dealData.amount.toString(),
dealstage: dealData.stage || 'appointmentscheduled',
pipeline: dealData.pipelineId || 'default',
closedate: dealData.closeDate,
dealtype: dealData.type || 'newbusiness',
description: dealData.description
}
};
const response = await hubspotRequest('/crm/v3/objects/deals', {
method: 'POST',
body: JSON.stringify(deal)
});
return response;
};
// مثال عملي
const deal = await createDeal({
name: 'Acme Corp - Enterprise License',
amount: 50000,
stage: 'qualification',
closeDate: '2026-06-30',
type: 'newbusiness',
description: 'Enterprise annual subscription'
});
// ربط الصفقة بالشركة وجهة الاتصال
await hubspotRequest(
`/crm/v3/objects/deals/${deal.id}/associations/companies/${companyId}`,
{ method: 'PUT', body: JSON.stringify({ types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 5 }] }) }
);
await hubspotRequest(
`/crm/v3/objects/deals/${deal.id}/associations/contacts/${contactId}`,
{ method: 'PUT', body: JSON.stringify({ types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 3 }] }) }
);
مراحل الصفقة (مسار العمل الافتراضي)
| المرحلة | القيمة الداخلية |
|---|---|
| المواعيد المحددة | appointmentscheduled |
| مؤهل للشراء | qualifiedtobuy |
| تم تحديد موعد العرض | presentationscheduled |
| صاحب القرار موافق | decisionmakerboughtin |
| تم إرسال العقد | contractsent |
| تم الفوز بالصفقة | closedwon |
| تم خسارة الصفقة | closedlost |
Webhooks
تكوين Webhooks
const createWebhook = async (webhookData) => {
const response = await hubspotRequest('/webhooks/v3/my-app/webhooks', {
method: 'POST',
body: JSON.stringify({
webhookUrl: webhookData.url,
eventTypes: webhookData.events,
objectType: webhookData.objectType,
propertyName: webhookData.propertyName // اختياري: تصفية حسب الخاصية
})
});
return response;
};
// مثال عملي
const webhook = await createWebhook({
url: 'https://myapp.com/webhooks/hubspot',
events: [
'contact.creation',
'contact.propertyChange',
'company.creation',
'deal.creation',
'deal.stageChange'
],
objectType: 'contact'
});
console.log(`Webhook created: ${webhook.id}`);
أنواع أحداث Webhook
| نوع الحدث | المشغل |
|---|---|
contact.creation |
تم إنشاء جهة اتصال جديدة |
contact.propertyChange |
تم تحديث خاصية جهة الاتصال |
contact.deletion |
تم حذف جهة اتصال |
company.creation |
تم إنشاء شركة جديدة |
company.propertyChange |
تم تحديث خاصية الشركة |
deal.creation |
تم إنشاء صفقة جديدة |
deal.stageChange |
تغيرت مرحلة الصفقة |
deal.propertyChange |
تم تحديث خاصية الصفقة |
ticket.creation |
تم إنشاء تذكرة جديدة |
ticket.propertyChange |
تم تحديث خاصية التذكرة |
التعامل مع Webhooks
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/hubspot', express.json(), async (req, res) => {
const signature = req.headers['x-hubspot-signature'];
const payload = JSON.stringify(req.body);
// تحقق من التوقيع
const isValid = verifyWebhookSignature(payload, signature, process.env.HUBSPOT_CLIENT_SECRET);
if (!isValid) {
console.error('Invalid webhook signature');
return res.status(401).send('Unauthorized');
}
const events = req.body;
for (const event of events) {
console.log(`Event: ${event.eventType}`);
console.log(`Object: ${event.objectType} - ${event.objectId}`);
console.log(`Property: ${event.propertyName}`);
console.log(`Value: ${event.propertyValue}`);
// التوجيه حسب نوع الحدث
switch (event.eventType) {
case 'contact.creation':
await handleContactCreation(event);
break;
case 'contact.propertyChange':
await handleContactUpdate(event);
break;
case 'deal.stageChange':
await handleDealStageChange(event);
break;
}
}
res.status(200).send('OK');
});
function verifyWebhookSignature(payload, signature, clientSecret) {
const expectedSignature = crypto
.createHmac('sha256', clientSecret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
تحديد المعدل (Rate Limiting)
فهم حدود المعدل
| المستوى | الطلبات/الثانية | الطلبات/اليوم |
|---|---|---|
| مجاني/مبتدئ | 100 | 100,000 |
| احترافي | 200 | 500,000 |
| مؤسسي | 400 | 1,000,000 |
عند تجاوز الحد، ستستقبل HTTP 429 (طلبات كثيرة جدًا).
رؤوس تحديد المعدل
| الرأس | الوصف |
|---|---|
X-HubSpot-RateLimit-Second-Limit |
الحد الأقصى للطلبات في الثانية |
X-HubSpot-RateLimit-Second-Remaining |
الطلبات المتبقية لهذه الثانية |
X-HubSpot-RateLimit-Second-Reset |
الثواني حتى إعادة تعيين حد الثانية |
X-HubSpot-RateLimit-Daily-Limit |
الحد الأقصى للطلبات في اليوم |
X-HubSpot-RateLimit-Daily-Remaining |
الطلبات المتبقية اليوم |
X-HubSpot-RateLimit-Daily-Reset |
الثواني حتى إعادة تعيين الحد اليومي |
تطبيق معالجة تحديد المعدل
const makeRateLimitedRequest = async (endpoint, options = {}, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await hubspotRequest(endpoint, options);
// عرض بيانات المعدل
const remaining = response.headers.get('X-HubSpot-RateLimit-Second-Remaining');
if (remaining < 10) {
console.warn(`Low rate limit remaining: ${remaining}`);
}
return response;
} catch (error) {
if (error.message.includes('429') && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
};
// كلاس منظم الطلبات
class HubSpotRateLimiter {
constructor(requestsPerSecond = 90) {
this.queue = [];
this.interval = 1000 / requestsPerSecond;
this.processing = false;
}
async add(requestFn) {
return new Promise((resolve, reject) => {
this.queue.push({ requestFn, resolve, reject });
this.process();
});
}
async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
const { requestFn, resolve, reject } = this.queue.shift();
try {
const result = await requestFn();
resolve(result);
} catch (error) {
reject(error);
}
if (this.queue.length > 0) {
await new Promise(r => setTimeout(r, this.interval));
}
}
this.processing = false;
}
}
قائمة التحقق من نشر الإنتاج
قبل الإطلاق، تأكد من:
- [ ] استخدام مصادقة التطبيقات الخاصة أو OAuth 2.0
- [ ] تخزين الرموز المميزة بأمان (قاعدة بيانات مشفرة)
- [ ] تنفيذ تحديث الرمز المميز تلقائيًا
- [ ] إعداد معالجة تحديد المعدل وقوائم الانتظار
- [ ] تفعيل نقطة نهاية webhook عبر HTTPS
- [ ] تطبيق معالجة أخطاء شاملة
- [ ] تسجيل جميع مكالمات API
- [ ] مراقبة حدود المعدل
- [ ] إعداد دليل لتشخيص الأخطاء
حالات استخدام واقعية
مزامنة CRM
- التحدي: إدخال بيانات العملاء يدويًا بين SaaS وHubSpot
- الحل: مزامنة فورية عبر Webhooks وAPI
- النتيجة: لا إدخال يدوي، دقة بيانات 100%
توجيه العملاء المحتملين
- التحدي: بطء استجابة العملاء المحتملين
- الحل: توزيع العملاء المحتملين تلقائيًا عبر Webhook للمبيعات
- النتيجة: وقت استجابة 5 دقائق، وزيادة التحويل 40%
الخلاصة
واجهة برمجة تطبيقات HubSpot تمنحك إمكانات قوية لإدارة علاقات العملاء وأتمتة التسويق. تلخيص النقاط:
- استخدم OAuth 2.0 للتطبيقات العامة، والتطبيقات الخاصة للتكاملات الداخلية
- حدود المعدل تعتمد على المستوى (100-400 طلب/ثانية)
- Webhooks تتيح مزامنة في الوقت الفعلي
- كائنات CRM تدعم الروابط والخصائص المخصصة
- Apidog يبسط اختبار وتوثيق وتعاون فرق تطوير الـ API
قسم الأسئلة الشائعة
كيف أقوم بالمصادقة مع واجهة برمجة تطبيقات HubSpot؟
استخدم OAuth 2.0 للتطبيقات متعددة المستأجرين أو التطبيقات الخاصة للتكاملات أحادية البوابة. تم إهمال مصادقة مفتاح API.
ما هي حدود معدل HubSpot؟
الحدود تتراوح من 100 طلب/ثانية (مجاني) حتى 400 طلب/ثانية (مؤسسي)، وحدود يومية من 100,000 إلى 1,000,000 طلب.
كيف أقوم بإنشاء جهة اتصال في HubSpot؟
ارسل طلب POST إلى /crm/v3/objects/contacts مع الخصائص مثل البريد الإلكتروني، الاسم الأول، الاسم الأخير، وأي حقول مخصصة.
هل يمكنني إنشاء خصائص مخصصة؟
نعم، استخدم واجهة برمجة تطبيقات الخصائص (Properties API) لإنشاء حقول مخصصة لأي كائن.
كيف تعمل Webhooks في HubSpot؟
قم بتكوين Webhooks في إعدادات التطبيق الخاص بك. سترسل HubSpot طلبات POST إلى نقطة النهاية لديك عند وقوع أحداث محددة.
Top comments (0)