Summary and recommendation
Syncro exposes a REST API at `https://{subdomain}.syncromsp.com/api/v1` authenticated via Bearer token (Admin > API Tokens).
There is no OAuth, no scopes - tokens inherit the full permission set of the technician who created them.
A token created by a restricted technician will silently return limited data or 403s on privileged endpoints;
always generate tokens from an Admin Technician account for full access.
The API manages customer-side objects only: contacts and customer organizations.
Technician (internal staff) accounts cannot be created, updated, or deleted via the REST API - that path is UI-only.
This is the most consequential caveat for any identity graph or provisioning integration targeting Syncro: the API cannot close the technician lifecycle loop.
Rate limits are enforced but not publicly documented.
HTTP 429 is returned on breach;
no Retry-After header is provided.
Pagination is offset-based using a `page` integer parameter with a default page size of 25 and a maximum of 100.
Always read `meta.total_pages` to determine full result set size.
API quick reference
| Has user API | Yes |
| Auth method | API Key (Bearer token in Authorization header) |
| Base URL | Official docs |
| SCIM available | No |
Authentication
Auth method: API Key (Bearer token in Authorization header)
Setup steps
- Log in to your Syncro account.
- Navigate to Admin > API Tokens.
- Click 'New Token', give it a name, and save.
- Copy the generated token.
- Pass the token in the Authorization header as: Authorization: Bearer {token}
Required scopes
| Scope | Description | Required for |
|---|---|---|
| N/A – token-level permissions | Syncro API tokens inherit the permissions of the technician who created them. There are no OAuth scopes; access is governed by the technician's role within the platform. | All API operations |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique identifier for the contact/customer user. | auto-assigned | read-only | Used as path parameter in endpoint URLs. |
| firstname | string | First name of the contact. | required | optional | |
| lastname | string | Last name of the contact. | required | optional | |
| string | Primary email address. | required | optional | Used for portal login and notifications. | |
| phone | string | Primary phone number. | optional | optional | |
| mobile | string | Mobile phone number. | optional | optional | |
| customer_id | integer | ID of the parent customer/organization this contact belongs to. | required | optional | Contacts are always scoped to a customer record. |
| address | string | Street address. | optional | optional | |
| address2 | string | Secondary address line. | optional | optional | |
| city | string | City. | optional | optional | |
| state | string | State or province. | optional | optional | |
| zip | string | Postal/ZIP code. | optional | optional | |
| notes | string | Free-text notes about the contact. | optional | optional | |
| opt_out | boolean | Whether the contact has opted out of marketing communications. | optional | optional | |
| created_at | datetime | ISO 8601 timestamp of record creation. | auto-assigned | read-only | |
| updated_at | datetime | ISO 8601 timestamp of last update. | auto-assigned | read-only |
Core endpoints
List contacts
- Method: GET
- URL:
https://{subdomain}.syncromsp.com/api/v1/contacts - Watch out for: Results are paginated at 25 per page by default. Use the
pageparam to iterate.
Request example
GET /api/v1/contacts?page=1
Authorization: Bearer {token}
Response example
{
"contacts": [
{"id": 101, "firstname": "Jane", "lastname": "Doe",
"email": "jane@example.com", "customer_id": 55}
],
"meta": {"total_pages": 3, "total_count": 72}
}
Get contact by ID
- Method: GET
- URL:
https://{subdomain}.syncromsp.com/api/v1/contacts/{id} - Watch out for: Returns 404 if the contact ID does not exist or belongs to a different subdomain.
Request example
GET /api/v1/contacts/101
Authorization: Bearer {token}
Response example
{
"contact": {
"id": 101,
"firstname": "Jane",
"lastname": "Doe",
"email": "jane@example.com",
"customer_id": 55
}
}
Create contact
- Method: POST
- URL:
https://{subdomain}.syncromsp.com/api/v1/contacts - Watch out for:
customer_idis required; contacts cannot exist without a parent customer record.
Request example
POST /api/v1/contacts
Authorization: Bearer {token}
Content-Type: application/json
{"firstname":"John","lastname":"Smith",
"email":"john@example.com","customer_id":55}
Response example
{
"contact": {
"id": 202,
"firstname": "John",
"lastname": "Smith",
"email": "john@example.com",
"customer_id": 55
}
}
Update contact
- Method: PUT
- URL:
https://{subdomain}.syncromsp.com/api/v1/contacts/{id} - Watch out for: Uses PUT (full or partial update accepted in practice); verify field behavior against the Swagger spec.
Request example
PUT /api/v1/contacts/202
Authorization: Bearer {token}
Content-Type: application/json
{"phone":"555-1234"}
Response example
{
"contact": {
"id": 202,
"phone": "555-1234"
}
}
Delete contact
- Method: DELETE
- URL:
https://{subdomain}.syncromsp.com/api/v1/contacts/{id} - Watch out for: Deletion is permanent. Associated tickets may retain the contact reference as orphaned data.
Request example
DELETE /api/v1/contacts/202
Authorization: Bearer {token}
Response example
HTTP 200 OK
{}
List customers (organizations)
- Method: GET
- URL:
https://{subdomain}.syncromsp.com/api/v1/customers - Watch out for: Customers and contacts are separate objects. Contacts are sub-records of customers.
Request example
GET /api/v1/customers?page=1
Authorization: Bearer {token}
Response example
{
"customers": [
{"id": 55, "firstname": "Acme", "email": "admin@acme.com"}
],
"meta": {"total_pages": 1, "total_count": 1}
}
Create customer
- Method: POST
- URL:
https://{subdomain}.syncromsp.com/api/v1/customers - Watch out for: Technician (internal) users cannot be created via the API; only customer-side contacts and organizations are manageable through the REST API.
Request example
POST /api/v1/customers
Authorization: Bearer {token}
Content-Type: application/json
{"firstname":"Acme Corp","email":"admin@acme.com"}
Response example
{
"customer": {
"id": 56,
"firstname": "Acme Corp",
"email": "admin@acme.com"
}
}
Get customer by ID
- Method: GET
- URL:
https://{subdomain}.syncromsp.com/api/v1/customers/{id}
Request example
GET /api/v1/customers/55
Authorization: Bearer {token}
Response example
{
"customer": {
"id": 55,
"firstname": "Acme Corp",
"email": "admin@acme.com",
"created_at": "2023-01-10T12:00:00Z"
}
}
Rate limits, pagination, and events
- Rate limits: Syncro enforces rate limiting on API requests. The official docs note a limit but do not publish a specific per-minute or per-hour number publicly.
- Rate-limit headers: No
- Retry-After header: No
- Rate-limit notes: Official docs do not specify rate-limit headers or Retry-After behavior. HTTP 429 is returned when the limit is exceeded.
- Pagination method: offset
- Default page size: 25
- Max page size: 100
- Pagination pointer: page
| Plan | Limit | Concurrent |
|---|---|---|
| All plans | Not publicly documented | 0 |
- Webhooks available: Yes
- Webhook notes: Syncro supports outbound webhooks triggered by platform events. Webhooks are configured in Admin > Webhooks and deliver JSON payloads via HTTP POST to a specified URL.
- Alternative event strategy: Poll the REST API for changes if webhook delivery is not suitable.
- Webhook events: ticket.created, ticket.updated, ticket.resolved, customer.created, customer.updated, contact.created, contact.updated, invoice.created, payment.received
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: Not documented
- Endpoint: Not documented
Limitations:
- Syncro does not document a SCIM 2.0 endpoint for technician provisioning.
- No IdP (Okta, Entra ID, Google Workspace, OneLogin) SCIM integration is documented in official help or developer docs.
- Technician user management is UI-only within the Syncro admin panel.
Common scenarios
Three integration patterns are well-supported by the current API surface.
Provisioning a new customer contact from an external system: check for the parent customer via GET /api/v1/customers?query={value}, create it if absent via POST /api/v1/customers, then create the contact via POST /api/v1/contacts with customer_id set to the returned customer ID.
Contacts cannot exist without a valid parent customer - omitting customer_id returns a validation error.
Syncing contact updates from an external directory: retrieve the stored contact via GET /api/v1/contacts/{id}, diff against your source of truth, and issue PUT /api/v1/contacts/{id} with updated fields.
There is no PATCH endpoint;
PUT is the only update method.
Sending partial fields may work in practice but verify against the Swagger spec at api-docs.syncromsp.com to avoid unintentional field nullification.
Event-driven enrichment via webhooks: configure a customer.created webhook in Admin > Webhooks pointing to your ingest endpoint.
On receipt, extract the customer ID and follow up with GET /api/v1/customers/{id} - webhook payloads do not guarantee full object detail, so the follow-up GET is required for complete data.
Provision a new customer contact from an external system
- Check if the parent customer exists: GET /api/v1/customers?query={email_or_name}
- If not found, create the customer: POST /api/v1/customers with firstname and email.
- Note the returned customer
id. - Create the contact: POST /api/v1/contacts with firstname, lastname, email, and customer_id set to the customer id from step 3.
- Store the returned contact
idin your external system for future updates.
Watch out for: Contacts require a valid customer_id. Attempting to create a contact without a pre-existing customer will fail with a validation error.
Sync contact updates from an external directory
- Retrieve the contact by stored ID: GET /api/v1/contacts/{id}
- Compare fields (email, phone, address) against your directory source of truth.
- If differences exist, issue PUT /api/v1/contacts/{id} with the updated fields.
- Log the updated_at timestamp from the response for audit purposes.
Watch out for: There is no PATCH endpoint; use PUT. Sending only changed fields may work but verify against the Swagger spec to avoid unintentional field nullification.
Detect new customers via webhook and enrich in external CRM
- Configure a webhook in Syncro Admin > Webhooks targeting your CRM ingest endpoint.
- Select the customer.created event.
- On receipt of the webhook payload, extract the customer id.
- Call GET /api/v1/customers/{id} to retrieve full customer details.
- Write the enriched record to your CRM.
Watch out for: Webhook payloads may not include all customer fields. Always follow up with a GET request to retrieve the complete object.
Why building this yourself is a trap
The primary integration trap is scope mismatch: the Syncro REST API is scoped to customer-facing contacts and organizations, not to the technician identity layer.
Any identity graph that needs to reflect internal staff provisioning state - who has access, at what permission level, and whether they are active - cannot be built from the API alone. That data lives exclusively in the UI.
A secondary trap is token permission inheritance. Because tokens carry the creating technician's permissions with no independent scope configuration, a token rotation or ownership change silently alters what the integration can read or write. There is no way to issue a least-privilege token for a specific endpoint subset.
Finally, the undocumented rate limit creates operational risk for high-frequency sync jobs. Without a published limit or Retry-After header, integrations must implement conservative backoff logic empirically rather than against a known ceiling.
The Swagger spec at api-docs.syncromsp.com is the authoritative field reference and should be treated as the source of truth over help center articles, which may lag API changes.
Automate Syncro workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.