The Customer API provides a retry-safe boundary between SalesPro Hub and CRMs, accounting systems, or ERP customer masters. Every record is keyed by both an external system and that system's immutable customer ID.
This is a REST integration surface. It is not a native HubSpot, Salesforce, Xero, QuickBooks, Sage, or Pastel OAuth connector.
Permissions
customers:read— list and retrieve customer sync datacustomers:write— upsert and deactivate externally managed customers
External Identity
Examples:
hubspot / 123456xero / 7f73d650-83c8-4f44-b09d-73e61c29a98csage / CUS-00042
The tuple (tenant, external_system, external_id) is unique. The same external
ID can safely exist in two different source systems.
Upsert a Customer
PUT /api/v1/customers/{externalSystem}/{externalId}The operation is idempotent. A new record returns 201; a retry or update
returns 200.
curl -X PUT "https://portal.salesrepsoftware.co.za/api/v1/customers/hubspot/123456" \
-H "X-API-Key: sk_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "ABC Trading",
"customer_code": "ABC-001",
"contact_person": "Lebo Nkosi",
"email": "orders@abctrading.co.za",
"phone": "+27 11 555 0123",
"address": "1 Main Road",
"city": "Johannesburg",
"province": "Gauteng",
"postal_code": "2001",
"metadata": {
"lifecycle_stage": "customer"
}
}'name is required. Latitude and longitude must be supplied together. Set
create_default_store to false when the customer should not receive an
initial sales outlet; it defaults to true on first creation. Replays never
create duplicate default outlets.
The default outlet is a starting location for route planning and order capture. Later outlet changes remain independent from the CRM customer record.
List Customers
GET /api/v1/customers| Parameter | Description |
|---|---|
updated_since | ISO 8601 cursor timestamp |
updated_since_id | Cursor tie-breaker returned by the API |
is_active | true or false |
include_deleted | Include soft-deleted tombstones |
per_page | 1–100; default 50 |
page | Traditional page number |
When updated_since is present, deleted tombstones are included by default so
a downstream CRM can remove or archive records. Initial full-list requests
exclude deleted records unless include_deleted=true.
{
"success": true,
"data": [
{
"external_system": "hubspot",
"external_id": "123456",
"customer_code": "ABC-001",
"name": "ABC Trading",
"contact_person": "Lebo Nkosi",
"email": "orders@abctrading.co.za",
"phone": "+27 11 555 0123",
"city": "Johannesburg",
"is_active": true,
"deleted_at": null,
"updated_at": "2026-07-23T10:00:00+00:00"
}
],
"meta": {
"total": 1,
"page": 1,
"per_page": 50,
"last_page": 1,
"next_cursor": {
"updated_since": "2026-07-23T10:00:00.000000Z",
"updated_since_id": 124
}
}
}Always persist and replay both cursor fields. The ID tie-breaker prevents gaps
when several customers share an updated_at timestamp.
Retrieve One Customer
GET /api/v1/customers/{externalSystem}/{externalId}This endpoint can return a deleted tombstone so integrations can reconcile the source identity.
Deactivate a Customer
DELETE /api/v1/customers/{externalSystem}/{externalId}Deletion through this API is a retry-safe deactivation (is_active=false).
The external identity mapping is retained. A later upsert reactivates the
record.
Conflict Policy
- External identity is authoritative for matching; names, emails, and phone numbers are not used as merge keys.
- A request cannot read or mutate another tenant's records.
- The API never silently reassigns an external identity to another customer.
- Use immutable source IDs rather than mutable account names or emails.