Skip to content
Documentation

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:

RecordAPI fieldWidget identify counterpartIn system binding
Contactexternal_iduser_id{external_id}
Companyexternal_idcompany.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