{
  "openapi": "3.1.0",
  "info": {
    "title": "emberry Developer API",
    "version": "1.0.0",
    "description": "Read and write your account's feedback, cases, locations, links and respondents, and receive signed webhooks. Available on Premium and Enterprise plans. See https://www.emberry.com.au/developers and docs/developer-api.md.",
    "contact": { "name": "emberry support", "email": "support@emberry.com.au" }
  },
  "servers": [{ "url": "https://www.emberry.com.au/api/v1" }],
  "security": [{ "bearerAuth": [] }],
  "tags": [
    { "name": "Submissions" }, { "name": "Cases" }, { "name": "Sites" },
    { "name": "Links" }, { "name": "Surface areas" }, { "name": "Respondents" },
    { "name": "Analytics" }
  ],
  "paths": {
    "/submissions": {
      "get": {
        "tags": ["Submissions"],
        "summary": "List feedback (scope: submissions:read; contact details + raw text with submissions:read_pii)",
        "parameters": [
          { "$ref": "#/components/parameters/limit" },
          { "$ref": "#/components/parameters/cursor" }
        ],
        "responses": {
          "200": { "description": "A page of submissions", "content": { "application/json": { "schema": {
            "type": "object",
            "properties": {
              "data": { "type": "array", "items": { "$ref": "#/components/schemas/Submission" } },
              "next_cursor": { "type": ["string", "null"] }
            }
          } } } },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/submissions/{id}": {
      "get": {
        "tags": ["Submissions"],
        "summary": "Get one submission (scope: submissions:read)",
        "parameters": [{ "$ref": "#/components/parameters/id" }],
        "responses": {
          "200": { "description": "The submission", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Submission" } } } } } },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/cases": {
      "get": {
        "tags": ["Cases"], "summary": "List cases (scope: cases:read)",
        "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }],
        "responses": { "200": { "description": "A page of cases", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Case" } }, "next_cursor": { "type": ["string", "null"] } } } } } } }
      },
      "post": {
        "tags": ["Cases"], "summary": "Open a case (scope: cases:write). NOT available via the API yet — open cases in the app; the API can read + update them.",
        "parameters": [{ "$ref": "#/components/parameters/idempotencyKey" }, { "$ref": "#/components/parameters/idempotencyKeyQuery" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": {
          "type": "object", "required": ["site_id"],
          "properties": {
            "site_id": { "type": "string" }, "summary": { "type": "string" },
            "priority": { "type": "string", "enum": ["low", "medium", "high"] },
            "surface_area_id": { "type": "string" }, "assigned_to": { "type": "string" }
          }
        } } } },
        "responses": {
          "201": { "description": "Created", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Case" } } } } } },
          "422": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/cases/{id}": {
      "get": { "tags": ["Cases"], "summary": "Get one case (scope: cases:read)", "parameters": [{ "$ref": "#/components/parameters/id" }], "responses": { "200": { "description": "The case", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Case" } } } } } }, "404": { "$ref": "#/components/responses/Error" } } },
      "patch": {
        "tags": ["Cases"], "summary": "Update a case (scope: cases:write). Setting status=resolved fires case.resolved.",
        "parameters": [{ "$ref": "#/components/parameters/id" }, { "$ref": "#/components/parameters/idempotencyKey" }, { "$ref": "#/components/parameters/idempotencyKeyQuery" }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": {
          "status": { "type": "string", "enum": ["open", "inProgress", "resolved", "closed"] },
          "priority": { "type": "string", "enum": ["low", "medium", "high"] },
          "assigned_to": { "type": "string" }, "summary": { "type": "string" }
        } } } } },
        "responses": { "200": { "description": "Updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Case" } } } } } }, "404": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/sites": {
      "get": { "tags": ["Sites"], "summary": "List locations (scope: sites:read)", "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }], "responses": { "200": { "description": "A page of locations", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Site" } }, "next_cursor": { "type": ["string", "null"] } } } } } } } },
      "post": {
        "tags": ["Sites"], "summary": "Create a location (scope: sites:write). NOT available via the API yet — adding a location is a billed change; use Setup.",
        "parameters": [{ "$ref": "#/components/parameters/idempotencyKey" }, { "$ref": "#/components/parameters/idempotencyKeyQuery" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "slug": { "type": "string" }, "contact_email": { "type": "string" }, "contact_phone": { "type": "string" }, "otp_enabled": { "type": "boolean" }, "anonymous_enabled": { "type": "boolean" }, "google_review_enabled": { "type": "boolean" } } } } } },
        "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Site" } } } } } }, "422": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/sites/{id}": {
      "get": { "tags": ["Sites"], "summary": "Get one location (scope: sites:read)", "parameters": [{ "$ref": "#/components/parameters/id" }], "responses": { "200": { "description": "The location", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Site" } } } } } }, "404": { "$ref": "#/components/responses/Error" } } },
      "patch": { "tags": ["Sites"], "summary": "Update a location (scope: sites:write)", "parameters": [{ "$ref": "#/components/parameters/id" }, { "$ref": "#/components/parameters/idempotencyKey" }, { "$ref": "#/components/parameters/idempotencyKeyQuery" }], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "contact_email": { "type": "string" }, "contact_phone": { "type": "string" }, "otp_enabled": { "type": "boolean" }, "anonymous_enabled": { "type": "boolean" }, "google_review_enabled": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Site" } } } } } }, "404": { "$ref": "#/components/responses/Error" } } }
    },
    "/links": {
      "get": { "tags": ["Links"], "summary": "List feedback links (scope: links:read)", "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }], "responses": { "200": { "description": "A page of links", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Link" } }, "next_cursor": { "type": ["string", "null"] } } } } } } } },
      "post": { "tags": ["Links"], "summary": "Create a feedback link (scope: links:write). NOT available via the API yet — create links in Setup.", "parameters": [{ "$ref": "#/components/parameters/idempotencyKey" }, { "$ref": "#/components/parameters/idempotencyKeyQuery" }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["site_id"], "properties": { "site_id": { "type": "string" }, "slug": { "type": "string" }, "label": { "type": "string" }, "status": { "type": "string", "enum": ["draft", "live", "paused"] } } } } } }, "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Link" } } } } } }, "422": { "$ref": "#/components/responses/Error" } } }
    },
    "/links/{id}": {
      "get": { "tags": ["Links"], "summary": "Get one link (scope: links:read)", "parameters": [{ "$ref": "#/components/parameters/id" }], "responses": { "200": { "description": "The link", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Link" } } } } } }, "404": { "$ref": "#/components/responses/Error" } } },
      "patch": { "tags": ["Links"], "summary": "Update a link (scope: links:write)", "parameters": [{ "$ref": "#/components/parameters/id" }, { "$ref": "#/components/parameters/idempotencyKey" }, { "$ref": "#/components/parameters/idempotencyKeyQuery" }], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "label": { "type": "string" }, "status": { "type": "string", "enum": ["draft", "live", "paused"] } } } } } }, "responses": { "200": { "description": "Updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Link" } } } } } }, "404": { "$ref": "#/components/responses/Error" } } }
    },
    "/surface-areas": {
      "get": { "tags": ["Surface areas"], "summary": "List surface areas (scope: sites:read)", "parameters": [{ "$ref": "#/components/parameters/limit" }, { "$ref": "#/components/parameters/cursor" }], "responses": { "200": { "description": "A page of surface areas", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/SurfaceArea" } }, "next_cursor": { "type": ["string", "null"] } } } } } } } }
    },
    "/respondents": {
      "post": { "tags": ["Respondents"], "summary": "Attach a note to a respondent by email (scope: respondents:write). The note appears on that person's respondent record; the email must already have identified feedback (respondents are derived from feedback).", "parameters": [{ "$ref": "#/components/parameters/idempotencyKey" }, { "$ref": "#/components/parameters/idempotencyKeyQuery" }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["email", "note"], "properties": { "email": { "type": "string" }, "note": { "type": "string" }, "author_email": { "type": "string" } } } } } }, "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "object", "properties": { "ok": { "type": "boolean" } } } } } } } }, "422": { "$ref": "#/components/responses/Error" } } }
    },
    "/analytics/nps": {
      "get": { "tags": ["Analytics"], "summary": "Net Promoter Score (scope: analytics:read)", "responses": { "200": { "description": "NPS breakdown", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "object", "properties": { "nps": { "type": ["integer", "null"] }, "promoters": { "type": "integer" }, "passives": { "type": "integer" }, "detractors": { "type": "integer" }, "scored_responses": { "type": "integer" }, "total_responses": { "type": "integer" }, "sampled": { "type": "boolean", "description": "true when the figures cover a recent sample (very large accounts), not the full history" } } } } } } } } } }
    },
    "/analytics/overview": {
      "get": { "tags": ["Analytics"], "summary": "Headline numbers (scope: analytics:read)", "responses": { "200": { "description": "Overview", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "object", "properties": { "total_responses": { "type": "integer" }, "average_rating": { "type": ["number", "null"] }, "open_cases": { "type": "integer" }, "sampled": { "type": "boolean", "description": "true when the figures cover a recent sample (very large accounts), not the full history" } } } } } } } } } }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Your secret API key, e.g. `Authorization: Bearer sk_live_…`. Scopes are listed per operation." }
    },
    "parameters": {
      "limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } },
      "cursor": { "name": "cursor", "in": "query", "schema": { "type": "string" }, "description": "Opaque cursor from a previous response's next_cursor." },
      "id": { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
      "idempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": false, "schema": { "type": "string" }, "description": "Idempotency key as a header. Repeat the same key on a retry to replay the original response instead of writing twice. Prefer the idempotency_key query parameter — some CDNs strip custom request headers. Writes only; remembered for 24 hours, scoped to your account." },
      "idempotencyKeyQuery": { "name": "idempotency_key", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Idempotency key as a query parameter (recommended). Repeat the same key on a retry to replay the original response instead of writing twice. Writes only; remembered for 24 hours, scoped to your account." }
    },
    "responses": {
      "Error": { "description": "Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "schemas": {
      "Error": { "type": "object", "properties": { "error": { "type": "string" }, "detail": { "type": "string" }, "request_id": { "type": "string" } }, "required": ["error"] },
      "Answer": { "type": "object", "properties": { "question_id": { "type": "string" }, "surface_area_id": { "type": "string" }, "widget": { "type": "string" }, "value": {}, "follow_up_chips": { "type": "array", "items": { "type": "string" } }, "follow_up_text": { "type": "string" } } },
      "Submission": { "type": "object", "properties": {
        "id": { "type": "string" }, "site_id": { "type": "string" }, "link_id": { "type": "string" },
        "audience_id": { "type": ["string", "null"] }, "channel": { "type": "string" },
        "sentiment": { "type": ["string", "null"] }, "nps_score": { "type": ["integer", "null"] },
        "mode": { "type": "string" }, "has_open_case": { "type": "boolean" }, "submitted_at": { "type": ["string", "null"] },
        "answers": { "type": "array", "items": { "$ref": "#/components/schemas/Answer" } },
        "respondent_alias": { "type": "string" }, "respondent_email": { "type": "string" }, "respondent_mobile": { "type": "string" }
      } },
      "Case": { "type": "object", "properties": {
        "id": { "type": "string" }, "status": { "type": "string" }, "priority": { "type": "string" },
        "site_id": { "type": "string" }, "submission_id": { "type": ["string", "null"] },
        "surface_area_id": { "type": ["string", "null"] }, "assigned_to": { "type": ["string", "null"] },
        "summary": { "type": ["string", "null"] }, "sla_due_at": { "type": ["string", "null"] },
        "resolved_at": { "type": ["string", "null"] }, "opened_at": { "type": ["string", "null"] }
      } },
      "Site": { "type": "object", "properties": {
        "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" },
        "status": { "type": ["string", "null"] }, "otp_enabled": { "type": "boolean" },
        "anonymous_enabled": { "type": "boolean" }, "google_review_enabled": { "type": "boolean" },
        "contact_email": { "type": ["string", "null"] }, "contact_phone": { "type": ["string", "null"] }, "timezone": { "type": ["string", "null"] }
      } },
      "Link": { "type": "object", "properties": {
        "id": { "type": "string" }, "slug": { "type": "string" }, "label": { "type": ["string", "null"] },
        "site_id": { "type": "string" }, "status": { "type": "string" }, "scope": { "type": "string" },
        "channels": { "type": "array", "items": { "type": "string" } },
        "surface_area_ids": { "type": "array", "items": { "type": "string" } },
        "audience_id": { "type": ["string", "null"] }, "exclude_from_aggregate": { "type": "boolean" }, "archived_at": { "type": ["string", "null"] }
      } },
      "SurfaceArea": { "type": "object", "properties": {
        "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" },
        "order": { "type": ["integer", "null"] }, "description": { "type": ["string", "null"] },
        "audience_ids": { "type": "array", "items": { "type": "string" } }
      } }
    }
  }
}
