InsideLoop.
WhyHow it worksFeaturesPricingAbout
Live DemoSign inSign upSign up→
WhyHow it worksFeaturesPricingAboutLive DemoSign in
Developers

API documentation

API version: v1

The InsideLoop API gives you programmatic, read-only access to your workspace’s data — survey responses, technician insights, surveys, and your synced client/technician roster — to pull into BI tools, reporting pipelines, or your own dashboards. All endpoints live under /api/v1 on the same domain you use for the app, return JSON, and require an API key.

Authentication

Create an API key under Settings → API keys. The full secret (it starts with sl_live_) is shown exactly once at creation — InsideLoop stores only a hash, so it can never be displayed again. Send it on every request as a bearer token:

Authorization: Bearer sl_live_...
  • Keys are scoped to your workspace — a key can only ever read its own workspace’s data.
  • Every key carries every scope — there is no partial-access key. Each endpoint below lists the scope it requires so you know what a key can reach; GET /api/v1/me (below) shows the full list for a given key.
  • Revoke a key at any time from Settings — revocation takes effect immediately.
  • Treat keys like passwords: keep them in a secret manager, never in client-side code or version control, and revoke immediately if one is exposed. Key creation and revocation are recorded in your audit log.

Read-only by design

The public API cannot create, modify, or delete anything in your workspace. Every endpoint is a GET; other HTTP methods return 405. Writes only happen through the signed-in app.

Rate limits

Each key may make 60 requests per minute. Beyond that, requests return 429 with a Retry-After header (seconds until the window resets). Back off and retry rather than hammering — for bulk pulls, page with limit and offset at a steady pace.

Errors

Failures return a consistent JSON body with a machine-readable code:

{
  "error": {
    "code": "insufficient_scope",
    "message": "This API key is missing the \"read:responses\" scope."
  }
}
StatusCodeMeaning
400invalid_parameterA query parameter is malformed or out of range.
401unauthorizedMissing, malformed, unknown, revoked, or expired API key.
403insufficient_scopeThe key is valid but lacks the scope this endpoint needs.
429rate_limitedOver 60 requests/minute on this key. Honor Retry-After.

Incremental sync with “since”

days + offset is fine for one-off pulls, but it’s the wrong tool for a recurring sync job: as new responses arrive, later pages shift underneath you, so an offset-based poll can silently skip or double-count rows. The responses and tech-insights endpoints instead support a since parameter (an ISO 8601 timestamp) built for polling:

  • Pass since and the endpoint switches from its default newest-first order to oldest-first, returning only rows strictly after that timestamp.
  • Take the received_at (or created_at) of the last row in the response and use it as since on your next call — that row is never returned again, so nothing repeats.
  • When a response returns fewer rows than limit, you’re caught up; wait and poll again with the same since.
  • Don’t combine since with offset or days — the moving cursor already tells the endpoint where to resume.

First call — everything since midnight:

curl -H "Authorization: Bearer sl_live_..." \
  "https://app.example.com/api/v1/responses?since=2026-07-01T00:00:00Z&limit=100"

Say the last row returned had "received_at": "2026-07-02T18:24:11.000Z". The next poll picks up right after it:

curl -H "Authorization: Bearer sl_live_..." \
  "https://app.example.com/api/v1/responses?since=2026-07-02T18:24:11.000Z&limit=100"

GET /api/v1/me

Key introspection: returns the workspace and key metadata. Works with any valid key (no scope required) — use it to verify a new key or debug a failing integration.

curl -H "Authorization: Bearer sl_live_..." \
  https://app.example.com/api/v1/me

Response:

{
  "workspace": { "id": "org_...", "name": "Your MSP" },
  "key": {
    "id": "ak_...",
    "name": "PowerBI export",
    "prefix": "sl_live_h2K9cPq7",
    "scopes": [
      "read:responses",
      "read:tech_insights",
      "read:surveys",
      "read:clients",
      "read:techs"
    ],
    "created_at": "2026-07-03T00:15:45.000Z",
    "expires_at": null
  }
}

GET /api/v1/responses

Lists survey responses. Requires the read:responses scope.

ParameterTypeDescription
daysintegerLook-back window in days, 1–365. Default 30. Ignored when since is set.
sincestringISO 8601 timestamp; return only responses received after it, oldest first. See “Incremental sync” above. Must be within the last 365 days.
sentimentstringFilter by sentiment: pos, neu, or neg.
survey_idstringOnly responses from this survey.
client_idstringOnly responses from this client company.
tech_idstringOnly responses attributed to this technician.
limitintegerPage size, 1–200. Default 50.
offsetintegerRows to skip for pagination. Default 0. Not meaningful with since — see “Incremental sync” above.
curl -H "Authorization: Bearer sl_live_..." \
  "https://app.example.com/api/v1/responses?days=30&sentiment=neg&limit=50"

Response:

{
  "data": [
    {
      "id": "resp_...",
      "received_at": "2026-07-02T18:24:11.000Z",
      "sentiment": "neg",
      "score": 1,
      "ticket_id": "T20260702.0042",
      "subject": "VPN keeps dropping",
      "comment": "Still not fixed after two calls.",
      "contact": "jane@client.com",
      "alert_sent": true,
      "client": { "id": "client_...", "name": "Acme Corp" },
      "tech": { "id": "tech_...", "name": "Sam Rivera" },
      "survey": { "id": "survey_...", "name": "Ticket CSAT", "type": "smiley" }
    }
  ],
  "pagination": { "limit": 50, "offset": 0, "returned": 1, "total": 1 }
}

pagination.total is the number of rows matching the filters; keep requesting with offset += limit until returned is less than limit. tech and survey can be null (e.g. relationship/NPS surveys aren’t attributed to a technician), and ticket_id can be null for responses not tied to a ticket.

GET /api/v1/tech-insights

Lists technician-submitted insights — concerns, opportunities, and other front-line feedback raised from inside a ticket. This is a separate stream from customer CSAT responses. Requires the read:tech_insights scope.

ParameterTypeDescription
daysintegerLook-back window in days, 1–365. Default 30. Ignored when since is set.
sincestringISO 8601 timestamp; return only insights created after it, oldest first. See “Incremental sync” above. Must be within the last 365 days.
statusstringFilter by status: open, acknowledged, or resolved.
categorystringFilter by category slug. Categories are configurable per workspace — see Settings.
client_idstringOnly insights raised about this client company.
tech_idstringOnly insights raised by this technician.
limitintegerPage size, 1–200. Default 50.
offsetintegerRows to skip for pagination. Default 0. Not meaningful with since.
curl -H "Authorization: Bearer sl_live_..." \
  "https://app.example.com/api/v1/tech-insights?days=30&status=open&limit=50"

Response:

{
  "data": [
    {
      "id": "ti_...",
      "created_at": "2026-07-10T14:02:00.000Z",
      "updated_at": "2026-07-10T14:02:00.000Z",
      "category": "opportunity",
      "note": "Client's switches are EOL, worth a refresh quote.",
      "status": "open",
      "ticket_id": "T20260710.0019",
      "client": { "id": "client_...", "name": "Acme Corp" },
      "tech": { "id": "tech_...", "name": "Sam Rivera" },
      "autotask_ticket": { "id": "12345", "number": "T20260710.0030", "status": "New" }
    }
  ],
  "pagination": { "limit": 50, "offset": 0, "returned": 1, "total": 1 }
}

client and tech can be null when the insight wasn’t attributed to one. autotask_ticket is null until the insight is converted into a ticket.

GET /api/v1/surveys

Lists every survey in the workspace. Requires the read:surveys scope. Not paginated.

curl -H "Authorization: Bearer sl_live_..." \
  https://app.example.com/api/v1/surveys

Response:

{
  "data": [
    {
      "id": "survey_...",
      "name": "Ticket CSAT",
      "type": "smiley",
      "status": "active",
      "delivery_mode": "embed",
      "question": "How did we do on this ticket?",
      "description": "",
      "sent": 812,
      "responded": 340,
      "csat": 94,
      "created_at": "2026-01-04T16:00:00.000Z",
      "updated_at": "2026-06-30T09:12:00.000Z"
    }
  ]
}

csat is null until the survey has at least one response. Use a survey’s id as survey_id on /api/v1/responses.

GET /api/v1/clients

Lists every client company synced from your PSA. Requires the read:clients scope. Not paginated.

curl -H "Authorization: Bearer sl_live_..." \
  https://app.example.com/api/v1/clients

Response:

{
  "data": [
    {
      "id": "client_...",
      "name": "Acme Corp",
      "external_id": "29384",
      "source": "autotask"
    }
  ]
}

external_id is the company’s id in your PSA (e.g. an Autotask company id), or null if this client was created manually rather than synced. Use a client’s id as client_id on other endpoints.

GET /api/v1/techs

Lists every technician synced from your PSA. Requires the read:techs scope. Not paginated.

curl -H "Authorization: Bearer sl_live_..." \
  https://app.example.com/api/v1/techs

Response:

{
  "data": [
    {
      "id": "tech_...",
      "name": "Sam Rivera",
      "email": "sam@yourmsp.com",
      "external_id": "184",
      "source": "autotask"
    }
  ]
}

external_id is the technician’s resource id in your PSA, or null if this technician was created manually rather than synced. Use a technician’s id as tech_id on other endpoints.

Versioning

The API is versioned in the path (/api/v1). Within v1 we may add new endpoints and new response fields, but we won’t remove or rename existing fields or change their types — build your integration to ignore fields it doesn’t recognize. Breaking changes would ship as a new version path.

Questions

Need an endpoint that isn’t here yet, or hitting something unexpected? Contact support@insideloop.app.

InsideLoop.

Customer satisfaction surveys, built into every ticket. Purpose-built for MSPs running Autotask.

Product

WhyHow it worksFeaturesPricingCompare

Autotask

Autotask CSAT surveysAutotask email templates

Get started

Book a callSupport

Legal

TermsPrivacySecurity