Receber por email
← Voltar para o catálogo

SuperOps API Patterns

Use this skill when working with the SuperOps.ai GraphQL API - authentication, query building, mutations, pagination, rate limiting, and error handling. Covers Bearer token auth, cursor pagination, variable usage, and best practices for GraphQL integration with SuperOps.ai.

31estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: Apache-2.0

Como adicionar

/plugin marketplace add wyre-technology/msp-claude-plugins

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/superops-api-patterns/svg)](https://www.skillteca.com.br/skills/superops-api-patterns)

Skills relacionadas

Ver todas de Automação →

Alerta por categoria

Receba novas skills de Automação toda segunda

1 email curto, só com as skills novas de Automação. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

SuperOps.ai API Patterns

Overview

SuperOps.ai uses a GraphQL API for all integrations. Unlike REST APIs, GraphQL allows you to request exactly the data you need in a single request. This skill covers authentication, query patterns, mutations, pagination, rate limiting, and error handling.

Authentication

Bearer Token Authentication

SuperOps.ai uses Bearer token authentication. You need:

  1. API Token - Generated from your profile settings
  2. Customer Subdomain - Your SuperOps.ai subdomain

Required Headers

POST /msp
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
CustomerSubDomain: yourcompany

Generating an API Token

  1. Log in to SuperOps.ai
  2. Click settings icon > "My Profile"
  3. Navigate to "API token" tab
  4. Click "Generate token"
  5. Copy and securely store the token

Note: You can only have one active API token. Regenerating creates a new token and invalidates the old one.

Environment Variables

export SUPEROPS_API_KEY="your-api-token"
export SUPEROPS_SUBDOMAIN="yourcompany"
export SUPEROPS_REGION="us"  # or "eu"

API Endpoints

SuperOps.ai provides region-specific endpoints:

| Platform | Region | Endpoint | |----------|--------|----------| | MSP | US | https://api.superops.ai/msp | | MSP | EU | https://euapi.superops.ai/msp | | IT | US | https://api.superops.ai/it | | IT | EU | https://euapi.superops.ai/it |

GraphQL Request Format

Basic Structure

{
  "query": "query or mutation string",
  "variables": {
    "variableName": "value"
  }
}

Query Example

query getClientList($input: ListInfoInput!) {
  getClientList(input: $input) {
    clients {
      accountId
      name
      status
    }
    listInfo {
      totalCount
      hasNextPage
      endCursor
    }
  }
}

Variables:

{
  "input": {
    "first": 50,
    "filter": {
      "status": "Active"
    }
  }
}

Mutation Example

mutation createTicket($input: CreateTicketInput!) {
  createTicket(input: $input) {
    ticketId
    ticketNumber
    subject
    status
  }
}

Variables:

{
  "input": {
    "subject": "Issue with email",
    "client": {
      "accountId": "client-uuid"
    },
    "priority": "HIGH"
  }
}

Cursor-Based Pagination

SuperOps.ai uses cursor-based pagination for large result sets.

Pagination Parameters

| Parameter | Type | Description | |-----------|------|-------------| | first | Int | Number of items to return (max 500) | | after | String | Cursor for next page | | before | String | Cursor for previous page | | last | Int | Number of items from end |

Pagination Response

{
  "data": {
    "getAssetList": {
      "assets": [...],
      "listInfo": {
        "totalCount": 1250,
        "hasNextPage": true,
        "hasPreviousPage": false,
        "startCursor": "YXJyYXljb25uZWN0aW9uOjA=",
        "endCursor": "YXJyYXljb25uZWN0aW9uOjQ5"
      }
    }
  }
}

Pagination Pattern

query getAssetListPaginated($input: ListInfoInput!) {
  getAssetList(input: $input) {
    assets {
      assetId
      name
    }
    listInfo {
      totalCount
      hasNextPage
      endCursor
    }
  }
}

First page:

{
  "input": {
    "first": 100
  }
}

Next page:

{
  "input": {
    "first": 100,
    "after": "YXJyYXljb25uZWN0aW9uOjk5"
  }
}

Complete Pagination Implementation

async function fetchAllAssets(filter = {}) {
  const allAssets = [];
  let hasNextPage = true;
  let cursor = null;

  while (hasNextPage) {
    const variables = {
      input: {
        first: 100,
        filter,
        ...(cursor && { after: cursor })
      }
    };

    const response = await graphqlRequest(GET_ASSETS_QUERY, variables);
    const { assets, listInfo } = response.data.getAssetList;

    allAssets.push(...assets);
    hasNextPage = listInfo.hasNextPage;
    cursor = listInfo.endCursor;
  }

  return allAssets;
}

Rate Limiting

Rate Limit Details

  • Limit: 800 requests per minute
  • Scope: Per API token
  • Reset: Rolling 60-second window

Rate Limit Headers

X-RateLimit-Limit: 800
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1708012345

Rate Limit Response (HTTP 429)

{
  "errors": [
    {
      "message": "Rate limit exceeded. Please retry after 30 seconds.",
      "extensions": {
        "code": "RATE_LIMITED",
        "retryAfter": 30
      }
    }
  ]
}

Retry Strategy

async function requestWithRetry(query, variables, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await graphqlRequest(query, variables);

      if (response.errors?.some(e => e.extensions?.code === 'RATE_LIMITED')) {
        const retryAfter = response.errors[0].extensions.retryAfter || 30;
        const jitter = Math.random() * 1000;
        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);
    }
  }
}

Query Filtering

Filter Operators

| Operator | Description | Example | |----------|-------------|---------| | eq | Equals | { "status": "Active" } | | ne | Not equals | { "status": { "ne": "Closed" } } | | in | In array | { "status": ["Open", "In Progress"] } | | contains | Contains substring | { "name": { "contains": "Acme" } } | | startsWith | Starts with | { "name": { "startsWith": "A" } } | | gt | Greater than | { "createdTime": { "gt": "2024-01-01" } } | | gte | Greater than or equal | { "priority": { "gte": "HIGH" } } | | lt | Less than | { "createdTime": { "lt": "2024-02-01" } } | | lte | Less than or equal | { "count": { "lte": 10 } } |

Complex Filter Example

{
  "input": {
    "filter": {
      "and": [
        { "status": ["Open", "In Progress"] },
        { "priority": { "in": ["Critical", "High"] } },
        {
          "or": [
            { "client": { "accountId": "client-1" } },
            { "client": { "accountId": "client-2" } }
          ]
        }
      ]
    }
  }
}

Ordering Results

{
  "input": {
    "orderBy": {
      "field": "createdTime",
      "direction": "DESC"
    }
  }
}

Date/Time Handling

Format Requirements

All dates and times must be in UTC with ISO 8601 format:

2024-02-15T10:30:00Z

Date Range Queries

{
  "filter": {
    "createdTime": {
      "gte": "2024-02-01T00:00:00Z",
      "lte": "2024-02-29T23:59:59Z"
    }
  }
}

Relative Date Calculation

// Get tickets from last 7 days
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);

const variables = {
  input: {
    filter: {
      createdTime: {
        gte: sevenDaysAgo.toISOString()
      }
    }
  }
};

Error Handling

GraphQL Error Response

{
  "data": null,
  "errors": [
    {
      "message": "Client not found",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["getClient"],
      "extensions": {
        "code": "NOT_FOUND",
        "field": "accountId"
      }
    }
  ]
}

Common Error Codes

| Code | Description | Resolution | |------|-------------|------------| | UNAUTHENTICATED | Invalid/missing token | Check API token | | FORBIDDEN | Insufficient permissions | Check user role | | NOT_FOUND | Entity doesn't exist | Verify ID | | BAD_REQUEST | Invalid input | Check query/variables | | RATE_LIMITED | Too many requests | Implement backoff | | INTERNAL_ERROR | Server error | Retry with backoff |

Error Handling Pattern

async function safeGraphQLRequest(query, variables) {
  try {
    const response = await graphqlRequest(query, variables
Compartilhar X LinkedIn