API
API Reference
Customer
Customer upload

Customer upload

Import customer data into Customerscore.io via the Customers API endpoint.

For interactive API documentation, see the Swagger reference (opens in a new tab).

Endpoint

MethodURL
POSThttps://api.customerscore.io/api/v1/customers

Request Body

The customers field is mandatory in the JSON body. Each customer object within the customers array must include the following attributes:

FieldTypeRequiredDescription
external_idstringYesIdentifier for the customer, max 255 characters
namestringYesName of the customer, max 255 characters
owner_emailstringNoOwner's email address, max 255 characters
parent_external_idstringNoexternal_id of the parent company, max 255 characters. See Parent company field
attributesobjectNoCustomer attributes object
metricsarrayNoArray of metric objects (up to 200 items)

Example Request

curl -X POST "https://api.customerscore.io/api/v1/customers" \
  -H "Content-Type: application/json" \
  -H "customerscore-key: your-generated-key" \
  -d '{
    "customers": [
      {
        "external_id": "12345",
        "name": "Knapp-Cruz Inc.",
        "owner_email": "[email protected]",
        "attributes": {
          "crm_link": "https://your-crm.com/12345",
          "contact_email": "[email protected]",
          "renewal_date": "2025-05-25"
        },
        "metrics": [
          {
            "date": "2024-04-29",
            "resolved_tickets": 39
          }
        ]
      }
    ]
  }'

Full Request Body Example

{
  "customers": [
    {
      "external_id": "12345",
      "name": "Knapp-Cruz Inc.",
      "owner_email": "[email protected]",
      "parent_external_id": "67890",
      "attributes": {
        "crm_link": "https://example.com",
        "contact_email": "[email protected]",
        "renewal_date": "2024-05-25",
        "country_name": "Czech Republic",
        "customers_count": 99,
        "has_avatar": true
      },
      "metrics": [
        {
          "date": "2024-04-29",
          "country": "Czechia",
          "has_picture": true,
          "resolved_tickets": 39,
          "created_at": "2024-08-15"
        }
      ]
    }
  ]
}

Batch Size

We strongly recommend sending customers in batches rather than one by one. Each request can include up to 100 customers, and the request body is limited to 5 MB.

For best performance and reliability, we recommend:

  • 50–100 customers per request
  • Request body size below 5 MB

Batching reduces network overhead and helps you stay within the rate limit. A request with more than 100 customers is rejected with 400 Bad Request and none of its customers are imported — split larger datasets into multiple requests.

Owner Email Field

If owner_email is provided, the customer will be automatically linked to the user in your account (if such a user exists).

Parent Company Field

parent_external_id places the customer under another customer in the company hierarchy — the parent/subsidiary tree shown on the Hierarchy tab of a customer's detail. It holds the external_id of the parent, not its name or internal ID.

{
  "customers": [
    { "external_id": "acme-group", "name": "Acme Group" },
    { "external_id": "acme-cz", "name": "Acme Czechia", "parent_external_id": "acme-group" },
    { "external_id": "acme-sk", "name": "Acme Slovakia", "parent_external_id": "acme-group" }
  ]
}
Value sentResult
field omittedThe current parent company is left untouched
"some-external-id"That customer becomes the parent company
null or ""The parent company is removed

Good to know

  • The parent may be created by the same request. Links are resolved after all customers in the payload have been created, so a group and its subsidiaries can be uploaded in one call — in any order.
  • Links are applied on a best-effort basis. The upload is processed asynchronously, so a link that cannot be used does not fail the request. It is skipped and recorded as a warning on the import, visible under Settings → Imports (opens in a new tab). This happens when:
    • parent_external_id matches no customer in your account
    • the customer points at itself
    • the link would create a cycle (A under B while B is already under A)
    • the resulting chain would be deeper than 10 levels
  • Only companies participate. Contacts are never picked up as a parent or a child, even when they share an external_id with a customer.
  • A hierarchy synced from a CRM wins. If your account syncs company hierarchy from HubSpot, the next sync overwrites what you set here.

Attributes Field

The attributes field is an object that contains useful information about a given customer. You can add:

  • System attributes: crm_link, contact_email, renewal_date
  • Custom attributes: Configured in the Customerscore.io application under Attributes (opens in a new tab)

Example Attributes Object

{
  "crm_link": "https://your-crm-link.com/12345",
  "contact_email": "[email protected]",
  "renewal_date": "2025-05-25",
  "country_name": "Czech Republic",
  "customers_count": 99,
  "has_avatar": true
}

Supported Value Types

TypeExample
String"abcd"
Number1234
Booleantrue or false
Date"2024-08-14"

Each key must precisely match the codename of the attribute configured in Customerscore.io. Keys are case-sensitive. Only matching keys will be stored and used for score calculation.

Metrics Field

The metrics field contains product-usage data that feeds into the health score calculation. It can hold up to 200 items.

FieldTypeRequiredDescription
datestringYesDate for the metric, must be unique in the array

Example Metrics Array

[
  {
    "date": "2024-04-29",
    "country": "Czechia",
    "has_picture": true,
    "resolved_tickets": 39,
    "created_at": "2024-08-15"
  }
]

Each key must precisely match the codename of the metric configured in Metrics (opens in a new tab). Keys are case-sensitive.

Data Source Precedence

Attributes and metrics are stored regardless of their data source — the API always takes precedence. This includes properties fed by another source (HubSpot, Stripe, a file import, …). Such a property keeps its data source, so the next sync from that source overwrites the value again. A property with no data source yet is assigned the API as its data source.

Values for calculated properties are ignored — they are derived from other values and recalculated automatically. Each ignored key is recorded as a warning on the import, visible under Settings → Imports (opens in a new tab).

Processing

Upon successful data import, internal processing will occur, including a scoring process that may take up to 30 minutes. After processing is complete, all users in the account will receive a notification regarding the newly imported customer data.

If the API is your account's source of truth, every external_id that does not exist yet is created as a new customer during processing and fires the customer.created webhook (with data.source = API). Existing customers are updated silently.

Response Codes

CodeDescription
200Customer data has been successfully received and forwarded for processing
400Bad request
401Unauthorized - Missing customerscore-key in the header
403Forbidden - Invalid key
405Method Not Allowed - Only POST method is allowed
406Not Acceptable
429Too Many Requests
490Unconfigured scoring