Stitchflow
Syncro logo

Syncro User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 16, 2026

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 APIYes
Auth methodAPI Key (Bearer token in Authorization header)
Base URLOfficial docs
SCIM availableNo

Authentication

Auth method: API Key (Bearer token in Authorization header)

Setup steps

  1. Log in to your Syncro account.
  2. Navigate to Admin > API Tokens.
  3. Click 'New Token', give it a name, and save.
  4. Copy the generated token.
  5. 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
email 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 page param 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_id is 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

  1. Check if the parent customer exists: GET /api/v1/customers?query={email_or_name}
  2. If not found, create the customer: POST /api/v1/customers with firstname and email.
  3. Note the returned customer id.
  4. Create the contact: POST /api/v1/contacts with firstname, lastname, email, and customer_id set to the customer id from step 3.
  5. Store the returned contact id in 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

  1. Retrieve the contact by stored ID: GET /api/v1/contacts/{id}
  2. Compare fields (email, phone, address) against your directory source of truth.
  3. If differences exist, issue PUT /api/v1/contacts/{id} with the updated fields.
  4. 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

  1. Configure a webhook in Syncro Admin > Webhooks targeting your CRM ingest endpoint.
  2. Select the customer.created event.
  3. On receipt of the webhook payload, extract the customer id.
  4. Call GET /api/v1/customers/{id} to retrieve full customer details.
  5. 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.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 16, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste