Contacts, companies and external ids
Map the user and company ids of your own system as external ids; create or update contacts by external id, link the company, send usage and revenue signals.
External ids: contact and company
The ids of your own system live in ClickFix as the external id (external_id). Contact and company external ids are separate fields, independent of each other and unique within the organization:
| Record | API field | Widget identify counterpart | In system binding |
|---|---|---|---|
| Contact | external_id | user_id | {external_id} |
| Company | external_id | company.id | {company_external_id} |
PUT /v1/public-api/contacts/by-external-id creates or updates the contact by external id (201 created, 200 updated). Matching is by external id only; no other contact is taken over through e-mail or phone. An id that belongs to another contact returns 409 EXTERNAL_ID_EXISTS. If you create the contact through the API first and the user later arrives through identify, no new contact is opened: the user is linked to the same contact, and a conversation an agent started before the customer visited the site (with contact_external_id) appears in the widget once the user signs in.
// Adım 2: kişi ve şirket için ayrı dış kimlik. user_id kişinin, company.id şirketin.
// @ts-check
ClickFix("identify", {
user_id: "1001", // API: contacts.external_id
user_hash: "SUNUCUDA_HESAPLANAN", // user_id + "\n" + company.id üzerinden imzalı
company: { id: "F-77", name: "Acme A.Ş.", domain: "acme.com.tr" }, // API: companies.external_id
});
ClickFix("on", "identify", ({ verified, company_verified }) =>
console.log("doğrulandı:", verified, "firma:", company_verified),
);// Adım 2: kişiyi dış kimliğiyle oluştur/güncelle, şirketi dış kimliğiyle bul.
import { createClient } from "@getclickfix/node";
const client = createClient({
baseURL: process.env.CLICKFIX_BASE_URL!, // https://api.getclickfix.com
apiKey: process.env.CLICKFIX_API_KEY!, // contacts:read, contacts:write, companies:read
});
// Aynı dış kimlikle ikinci çağrı yeni kişi açmaz, günceller (200); ilki 201 döner.
const contact = await client.request(
"/v1/public-api/contacts/by-external-id",
"put",
{ external_id: "1001", name: "Ayşe Yılmaz", email: "ayse@example.com" },
{ idempotencyKey: `user-1001-${Date.now()}` },
);
// Şirketin dış kimliği kişininkinden ayrıdır (widget: company.id).
const companies = await client.request(
"/v1/public-api/companies",
"get",
undefined,
{ query: { external_id: "F-77" } },
);
console.log(
JSON.stringify({ contact: contact.data, companies: companies.data }),
);package main
import (
"context"
"encoding/json"
"fmt"
"os"
"time"
clickfix "github.com/ClickSolveMainTR/clickfix-sdks/go"
)
// Adım 2: kişiyi dış kimliğiyle oluştur/güncelle, şirketi dış kimliğiyle bul.
func externalID(ctx context.Context) error {
client, err := clickfix.New(os.Getenv("CLICKFIX_BASE_URL"), os.Getenv("CLICKFIX_API_KEY"))
if err != nil {
return err
}
name, email := "Ayşe Yılmaz", "ayse@example.com"
key := fmt.Sprintf("user-1001-%d", time.Now().UnixNano())
res, err := client.PutV1PublicApiContactByExternalIdWithResponse(ctx,
&clickfix.PutV1PublicApiContactByExternalIdParams{IdempotencyKey: key},
clickfix.PutV1PublicApiContactByExternalIdJSONRequestBody{ExternalId: "1001", Name: &name, Email: &email})
if err != nil {
return err
}
if res.StatusCode() != 200 && res.StatusCode() != 201 { // 200 güncellendi, 201 oluşturuldu
return fmt.Errorf("clickfix: HTTP %d", res.StatusCode())
}
ext := "F-77" // şirketin dış kimliği (widget identify: company.id)
companies, err := client.GetV1PublicApiCompaniesWithResponse(ctx, &clickfix.GetV1PublicApiCompaniesParams{ExternalId: &ext})
if err != nil {
return err
}
return json.NewEncoder(os.Stdout).Encode(map[string]any{"contact": res.StatusCode(), "companies": companies.StatusCode()})
}<?php
// Adım 2: kişiyi dış kimliğiyle oluştur/güncelle, şirketi dış kimliğiyle bul.
require __DIR__.'/vendor/autoload.php'; // composer require clickfix/sdk guzzlehttp/guzzle
use ClickFix\Client;
$client = new Client(
getenv('CLICKFIX_BASE_URL'), // https://api.getclickfix.com
getenv('CLICKFIX_API_KEY'), // contacts:read, contacts:write, companies:read
);
// Aynı dış kimlikle ikinci çağrı yeni kişi açmaz, günceller (200); ilki 201 döner.
$contact = $client->contacts()->upsertByExternalId(
'1001',
['name' => 'Ayşe Yılmaz', 'email' => 'ayse@example.com'],
idempotencyKey: 'user-1001-'.(int) (microtime(true) * 1000),
);
// Şirketin dış kimliği kişininkinden ayrıdır (widget: company.id).
$company = $client->companies()->findByExternalId('F-77');
echo json_encode(['contact' => $contact, 'company' => $company]), PHP_EOL;# Adım 2: kişiyi dış kimliğiyle oluştur/güncelle (201 oluşturuldu, 200 güncellendi).
curl -sS --fail-with-body -X PUT "$CLICKFIX_BASE_URL/v1/public-api/contacts/by-external-id" \
-H "Authorization: Bearer $CLICKFIX_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: user-1001-$(date +%s)" \
-d '{ "external_id": "1001", "name": "Ayşe Yılmaz", "email": "ayse@example.com" }'
# Şirketi kendi dış kimliğiyle bul (kişi dış kimliğinden ayrıdır).
curl -sS --fail-with-body "$CLICKFIX_BASE_URL/v1/public-api/companies?external_id=F-77" \
-H "Authorization: Bearer $CLICKFIX_API_KEY"The identity_state field of contact and conversation responses is verified, anonymous or self_named; webhook events carry contact_external_id, contact_verified, company_uuid and company_external_id, so you match your own record without another request.
Company
A company is created or matched through company in the widget's identify call: the first key is company.id (the company's external id; used only when user_hash signs it too, see identity verification), the second is domain. A company bound through a signed id carries the Verified badge in the panel. Through the API a company is found with GET /v1/public-api/companies?external_id=; three customer-health signals are sent against it: usage (PUT /company-usage, 0–100), revenue (PUT /company-revenue) and product events (POST /company-events, next section). In all three the company is selected by company_uuid, external_id or domain.
// Adım 4: şirket identify ile oluşur ya da dış kimliğiyle eşleşir (ikinci anahtar: domain).
// company.id yalnız user_hash onu da imzalıyorsa bağlanır (user_id + "\n" + company.id).
// @ts-check
ClickFix("boot", {
widgetId: "WIDGET_ID",
user: {
user_id: "1001",
user_hash: "SUNUCUDA_HESAPLANAN", // user_id + "\n" + "F-77" üzerinden
company: { id: "F-77", name: "Acme A.Ş.", domain: "acme.com.tr" },
},
});// Adım 4: şirket. Şirket widget identify (company.id) ile oluşur; API ile
// bulunur ve müşteri sağlığı sinyalleri (kullanım, gelir, olay) gönderilir.
import { createClient } from "@getclickfix/node";
const client = createClient({
baseURL: process.env.CLICKFIX_BASE_URL!,
apiKey: process.env.CLICKFIX_API_KEY!, // companies:read, health:write
});
const found = await client.request(
"/v1/public-api/companies",
"get",
undefined,
{
query: { external_id: "F-77" },
},
);
// 0-100 arası kullanım sinyali; 30 gün boyunca sağlık puanına katılır.
const usage = await client.request(
"/v1/public-api/company-usage",
"put",
{ external_id: "F-77", score: 82 },
// İşlemi tanımlayan sabit değer: kendi ölçüm kaydınızın kimliği (örnekte zaman damgası)
{ idempotencyKey: `usage-F-77-${Date.now()}` },
);
console.log(JSON.stringify({ found: found.data, usage: usage.data }));package main
import (
"context"
"encoding/json"
"fmt"
"os"
"time"
clickfix "github.com/ClickSolveMainTR/clickfix-sdks/go"
)
// Adım 4: şirketi bul ve kullanım sinyali gönder (health:write).
func company(ctx context.Context) error {
client, err := clickfix.New(os.Getenv("CLICKFIX_BASE_URL"), os.Getenv("CLICKFIX_API_KEY"))
if err != nil {
return err
}
ext := "F-77"
found, err := client.GetV1PublicApiCompaniesWithResponse(ctx, &clickfix.GetV1PublicApiCompaniesParams{ExternalId: &ext})
if err != nil {
return err
}
usage, err := client.PutV1PublicApiCompanyUsageWithResponse(ctx,
// İşlemi tanımlayan sabit değer: kendi ölçüm kaydınızın kimliği (örnekte zaman damgası)
&clickfix.PutV1PublicApiCompanyUsageParams{IdempotencyKey: fmt.Sprintf("usage-F-77-%d", time.Now().UnixNano())},
clickfix.PutV1PublicApiCompanyUsageJSONRequestBody{ExternalId: &ext, Score: 82})
if err != nil {
return err
}
if usage.StatusCode() != 200 {
return fmt.Errorf("clickfix: HTTP %d", usage.StatusCode())
}
return json.NewEncoder(os.Stdout).Encode(map[string]int{"found": found.StatusCode(), "usage": usage.StatusCode()})
}<?php
// Adım 4: şirket. Şirket widget identify (company.id) ile oluşur; API ile
// bulunur ve müşteri sağlığı sinyalleri (kullanım, gelir, olay) gönderilir.
require __DIR__.'/vendor/autoload.php';
use ClickFix\Client;
$client = new Client(
getenv('CLICKFIX_BASE_URL'),
getenv('CLICKFIX_API_KEY'), // companies:read, health:write
);
$found = $client->companies()->findByExternalId('F-77');
// 0-100 arası kullanım sinyali; 30 gün boyunca sağlık puanına katılır.
$usage = $client->companies()->setUsage(
['external_id' => 'F-77', 'score' => 82],
// İşlemi tanımlayan sabit değer: kendi ölçüm kaydınızın kimliği (örnekte zaman damgası)
idempotencyKey: 'usage-F-77-'.(int) (microtime(true) * 1000),
);
echo json_encode(['found' => $found, 'usage' => $usage]), PHP_EOL;# Adım 4: şirket kullanım sinyali (0-100, health:write); şirket external_id ile bulunur.
curl -sS --fail-with-body -X PUT "$CLICKFIX_BASE_URL/v1/public-api/company-usage" \
-H "Authorization: Bearer $CLICKFIX_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: usage-F-77-$(date +%s%N)" \
-d '{ "external_id": "F-77", "score": 82 }'Last updated on