Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.insito.app/llms.txt

Use this file to discover all available pages before exploring further.

The SDK’s job is to wrap five endpoints into idiomatic mobile code. If you’re integrating from a platform we don’t have an SDK for yet (Flutter, Swift, Kotlin, web), call these directly. Base URL: https://api.insito.app/v1/sdk. See Authentication for the Bearer proj_xxx header.

POST /identify

Idempotent upsert of a respondent. Call once when your user signs in or as early as you have a stable userId.

Request

{
  "userId": "user-123",        // required, your stable identifier
  "platform": "ios",            // optional
  "appVersion": "2.7.0",        // optional
  "metadata": { "plan": "pro" } // optional, max 10 KB JSON
}

Response

{
  "respondentId": "550e8400-e29b-41d4-a716-446655440000"
}
Idempotent on (project_id, userId) — calling again with the same userId updates platform, appVersion, metadata, and last_seen_at but doesn’t create a new respondent.

POST /event

Trigger evaluation. Decides whether to show a survey.

Request

{
  "event": "checkout_completed",  // required, lowercase snake_case
  "userId": "user-123"             // required
}

Response (no survey)

{ "survey": null }
Reasons: user not yet identified, no active survey for this trigger, user is within the throttle window, plan is exhausted, or response limit reached on the survey.

Response (survey shown)

{
  "survey": {
    "surveyId": "uuid",
    "questions": [
      {
        "id": "uuid",
        "type": "nps",
        "text": "How likely are you to recommend us?",
        "options": null,
        "isRequired": true,
        "position": 1
      }
    ]
  }
}
options shape per question type:
  • nps: null — score is always 0–10
  • rating: { "max": 5 }
  • multiple_choice: { "choices": ["A", "B", "C"], "multiSelect": false }
  • open_text: { "maxLength": 280 }

POST /impression

Records that a survey was shown to a user. Sets the per-user throttle window in Redis. The SDK fires this right after rendering the modal — don’t call it from a wait, did the user see it? position.

Request

{
  "surveyId": "uuid",  // from the previous /event call
  "userId": "user-123"
}

Response

{ "ok": true }
Internal note: Redis failures here are non-fatal (the data row is written either way). The throttle key just has a slightly delayed TTL when Redis is unhealthy.

POST /response

Submit the user’s answers. Counts against your plan.

Request

{
  "surveyId": "uuid",
  "userId": "user-123",
  "answers": [
    { "questionId": "uuid", "type": "nps", "value": 9 },
    { "questionId": "uuid", "type": "open_text", "value": "Love it!" }
  ],
  "platform": "ios",       // optional snapshot
  "appVersion": "2.7.0"    // optional snapshot
}

Response (success)

{ "responseId": "550e8400-..." }

Response (plan exhausted)

{
  "error": "response_limit_reached",
  "details": { "upgradeUrl": "https://admin.insito.app/billing" }
}
Status 402 Payment Required. The SDK surfaces this as a response_failed event with reason: "response_limit_reached".

Answer value shapes

Question typevalue
npsInteger 0..10
ratingInteger 1..5
multiple_choice (single)String matching one of options.choices
multiple_choice (multi)Array of strings
open_textString, ≤ options.maxLength

POST /screen-map

Batch upsert of screen visits. The SDK aggregates locally for ~60s then flushes here. Send null or omit if you don’t use screen tracking.

Request

{
  "screens": {
    "/home": 12,
    "/settings": 3,
    "/checkout/success": 1
  }
}
Up to 200 paths per call.

Response

{ "ok": true }

Cross-cutting

All five endpoints:
  • Authenticate with Authorization: Bearer proj_xxx.
  • Take a JSON body (Content-Type: application/json).
  • Validate with zod — 400 returns a validation_failed body with the offending field path.
  • Return internal_error 500 on database failures (with a requestId for support correlation).

OpenAPI

We’re publishing a full OpenAPI 3.1 spec — track [INS-…] for the schedule. Right now this page is the canonical reference.