AgentSkillsCN

Api Patterns

当您需要对接Syncro MSP API时,可使用此技能:掌握身份认证、分页查询、速率限制与错误处理等核心功能。本技能涵盖API密钥的配置、请求模式、响应处理,以及API集成的最佳实践。

SKILL.md
--- frontmatter
description: >
  Use this skill when working with the Syncro MSP API - authentication,
  pagination, rate limiting, and error handling. Covers API key setup,
  request patterns, response handling, and best practices for API integration.
triggers:
  - syncro api
  - syncro authentication
  - syncro api key
  - syncro pagination
  - syncro rate limit
  - api error syncro
  - syncro rest api
  - syncro integration

Syncro MSP API Patterns

Overview

The Syncro MSP API provides access to tickets, customers, assets, invoices, and more. This skill covers authentication, pagination, rate limiting, error handling, and best practices for API integration.

Authentication

API Key Authentication

Syncro uses Bearer token authentication with API keys:

http
GET /api/v1/tickets
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Getting Your API Key

  1. Log into your Syncro MSP account
  2. Go to Admin > API Tokens (or User Profile)
  3. Generate a new API token
  4. Copy and securely store the token

Environment Variables

bash
export SYNCRO_API_KEY="your-api-key-here"
export SYNCRO_SUBDOMAIN="your-subdomain"  # e.g., "acme" for acme.syncromsp.com

Base URL Format

The API base URL uses your subdomain:

code
https://{subdomain}.syncromsp.com/api/v1/

Example:

code
https://acme.syncromsp.com/api/v1/tickets

Pagination

Page-Based Pagination

Syncro uses page-based pagination:

http
GET /api/v1/tickets?page=1
GET /api/v1/tickets?page=2
GET /api/v1/tickets?page=3

Pagination Parameters

ParameterDescriptionDefault
pagePage number (1-based)1

Response Metadata

Responses include pagination information:

json
{
  "tickets": [...],
  "meta": {
    "total_entries": 156,
    "total_pages": 7,
    "page": 1,
    "per_page": 25
  }
}

Efficient Pagination Pattern

javascript
async function fetchAllTickets(filter = {}) {
  const allItems = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const response = await fetch(
      `https://${SUBDOMAIN}.syncromsp.com/api/v1/tickets?page=${page}`,
      {
        headers: {
          'Authorization': `Bearer ${API_KEY}`,
          'Content-Type': 'application/json'
        }
      }
    );

    const data = await response.json();
    allItems.push(...data.tickets);

    hasMore = page < data.meta.total_pages;
    page++;

    // Respect rate limits
    await sleep(350); // ~170 req/min to stay under 180/min
  }

  return allItems;
}

Rate Limiting

Rate Limit Policy

Syncro enforces a rate limit of 180 requests per minute per IP address.

Rate Limit Response

When rate limited, you receive:

http
HTTP/1.1 429 Too Many Requests
Retry-After: 30
json
{
  "error": "Rate limit exceeded. Please wait before making more requests."
}

Retry Strategy

javascript
async function requestWithRetry(url, options, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After') || 30;
        const jitter = Math.random() * 1000;
        console.log(`Rate limited. Waiting ${retryAfter}s...`);
        await sleep(retryAfter * 1000 + jitter);
        continue;
      }

      return response;
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;

      // Exponential backoff with jitter
      const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
      await sleep(delay);
    }
  }
}

Batch Processing

For bulk operations, throttle requests:

javascript
async function batchProcess(items, processFunc, delayMs = 350) {
  const results = [];

  for (const item of items) {
    const result = await processFunc(item);
    results.push(result);
    await sleep(delayMs);
  }

  return results;
}

Request Patterns

GET - Retrieve Data

Single resource:

http
GET /api/v1/tickets/12345
Authorization: Bearer YOUR_API_KEY

List with filters:

http
GET /api/v1/tickets?customer_id=123&status=open&page=1
Authorization: Bearer YOUR_API_KEY

POST - Create Resources

http
POST /api/v1/tickets
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "customer_id": 12345,
  "subject": "New support request",
  "status": "New",
  "priority": "Medium"
}

PUT - Update Resources

http
PUT /api/v1/tickets/12345
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "status": "Resolved",
  "priority": "Low"
}

DELETE - Remove Resources

http
DELETE /api/v1/contacts/67890
Authorization: Bearer YOUR_API_KEY

Common Query Parameters

ParameterDescriptionExample
pagePage numberpage=2
querySearch termquery=email
customer_idFilter by customercustomer_id=123
date_fromStart datedate_from=2024-01-01
date_toEnd datedate_to=2024-01-31
mineCurrent user onlymine=true
statusStatus filterstatus=open

Error Handling

HTTP Status Codes

CodeMeaningAction
200SuccessProcess response
201CreatedResource created
400Bad RequestCheck request format
401UnauthorizedVerify API key
403ForbiddenCheck permissions
404Not FoundResource doesn't exist
422UnprocessableValidation failed
429Rate LimitedWait and retry
500Server ErrorRetry with backoff

Error Response Format

json
{
  "error": "Validation failed",
  "errors": [
    {
      "field": "customer_id",
      "message": "is required"
    }
  ]
}

Error Handling Pattern

javascript
async function makeRequest(url, options) {
  const response = await fetch(url, options);

  if (!response.ok) {
    const errorData = await response.json().catch(() => ({}));

    switch (response.status) {
      case 401:
        throw new Error('Invalid API key. Check your credentials.');
      case 403:
        throw new Error('Permission denied. Check API key permissions.');
      case 404:
        throw new Error('Resource not found.');
      case 422:
        const messages = errorData.errors?.map(e => `${e.field}: ${e.message}`).join(', ');
        throw new Error(`Validation failed: ${messages}`);
      case 429:
        throw new Error('Rate limited. Try again later.');
      default:
        throw new Error(`API error: ${response.status}`);
    }
  }

  return response.json();
}

Common Endpoints

Tickets

MethodEndpointDescription
GET/api/v1/ticketsList tickets
POST/api/v1/ticketsCreate ticket
GET/api/v1/tickets/{id}Get ticket
PUT/api/v1/tickets/{id}Update ticket
POST/api/v1/tickets/{id}/commentAdd comment
POST/api/v1/tickets/{id}/timerTimer operations

Customers

MethodEndpointDescription
GET/api/v1/customersList customers
POST/api/v1/customersCreate customer
GET/api/v1/customers/{id}Get customer
PUT/api/v1/customers/{id}Update customer

Contacts

MethodEndpointDescription
GET/api/v1/contactsList contacts
POST/api/v1/contactsCreate contact
GET/api/v1/contacts/{id}Get contact
PUT/api/v1/contacts/{id}Update contact
DELETE/api/v1/contacts/{id}Delete contact

Assets

MethodEndpointDescription
GET/api/v1/customer_assetsList assets
POST/api/v1/customer_assetsCreate asset
GET/api/v1/customer_assets/{id}Get asset
PUT/api/v1/customer_assets/{id}Update asset
DELETE/api/v1/customer_assets/{id}Delete asset
GET/api/v1/customer_assets/{id}/patchesGet patches

Invoices

MethodEndpointDescription
GET/api/v1/invoicesList invoices
POST/api/v1/invoicesCreate invoice
GET/api/v1/invoices/{id}Get invoice
PUT/api/v1/invoices/{id}Update invoice
POST/api/v1/invoices/{id}/emailEmail invoice
POST/api/v1/invoices/{id}/paymentsRecord payment

Best Practices

  1. Store API key securely - Use environment variables, never commit to code
  2. Use subdomain correctly - Ensure URL matches your account
  3. Implement retry logic - Handle rate limits and transient errors
  4. Paginate large requests - Don't fetch unbounded result sets
  5. Cache reference data - Reduce API calls for static lookups
  6. Log API calls - Enable debugging and audit trails
  7. Validate before sending - Check required fields client-side
  8. Handle errors gracefully - Provide meaningful error messages
  9. Respect rate limits - Space out requests appropriately
  10. Test in sandbox first - If available, use test environment

Request Example with cURL

bash
# List tickets
curl -X GET "https://acme.syncromsp.com/api/v1/tickets?page=1" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

# Create ticket
curl -X POST "https://acme.syncromsp.com/api/v1/tickets" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": 12345,
    "subject": "New ticket",
    "status": "New",
    "priority": "Medium"
  }'

Related Skills