# Nosie — full integration documentation > Nosie (nosie.app) runs brief, evidence-based micro-interviews with customers — by phone call, SMS/chat, or email — and returns structured results: a transcript, a summary, attributes mapped to a user-defined schema, and quality signals. A product of Ortomate Ltd., Wellington, New Zealand. Last updated: 6 July 2026. HTML versions: https://nosie.app/docs · https://nosie.app/docs/api · https://nosie.app/docs/webhooks. OpenAPI 3.1 spec: https://nosie.app/api/v1/openapi.json ## Integrating Nosie There are two ways to use Nosie: manually from the dashboard (no code), or programmatically through the REST API and webhooks. Both paths share the same projects, contacts, and results. ### Using the dashboard (no code) 1. Create a project: answer a short chat about what you want to learn. Nosie drafts a structured interview brief (objective, audience, key topics, attributes to extract) which you review and approve before anything goes live. 2. Add contacts: one at a time or by CSV import. CSV headers: name, phone, email, modes ("call|sms|email"), timezone, country — any other column becomes a custom field. Every add requires a consent attestation. 3. Launch: Nosie reaches each contact in their allowed modes within local calling hours, asks follow-ups, and respects opt-outs immediately and permanently. 4. Read results: each completed interview appears under the project's Results tab with summary, attributes, and quality signals — exportable as CSV or JSON. ### The consent rule (cannot be disabled) Every contact-create — dashboard, CSV, or API — must carry a consent attestation: - attested: literal true - basis: how consent was collected, minimum 10 characters (stored in the consent audit log) - method: one of signup_form | verbal | written | existing_relationship | other API requests without one are rejected with HTTP 422. Opt-outs are honoured immediately and can never be reversed, by anyone. ## REST API Base URL: https://nosie.app/api/v1 Auth: `Authorization: Bearer ` — keys are created in the dashboard (Developers page), shown once, prefixed nk_live_ Rate limit: 60 requests/minute per key (429 + Retry-After: 60 when exceeded) Content type: application/json. IDs are UUIDs. Errors are JSON: { "error": "" } with status 401 (bad/missing key), 404 (not found), 422 (validation / missing consent), 429 (rate limit). ### Endpoints - POST /v1/projects — create a project; body { name, brief } - GET /v1/projects/{id} — get a project - POST /v1/projects/{id}/contacts — add contacts; body { contacts: Contact[], consent: Consent }; 422 without consent - GET /v1/projects/{id}/contacts — list contacts - POST /v1/projects/{id}/launch — launch outreach - POST /v1/projects/{id}/pause — pause outreach - GET /v1/contacts/{id}/result — transcript, summary, attributes, quality, outreach history - GET /v1/webhooks — list webhooks - POST /v1/webhooks — create a webhook (signing secret returned once) - DELETE /v1/webhooks/{id} — delete a webhook ### Brief schema (required on project create) - objective (string, required): what you want to learn - audience_description (string, required): who is being interviewed - key_topics (string[], required): 3–6 topics the conversation must cover - success_criteria (string, required): what a successful interview produces - identity_label (string, required): who Nosie says it's calling on behalf of - tone (string, optional): default "warm, concise, respectful" - allowed_modes (("call"|"sms"|"email")[], required) - timebox_seconds (integer, optional): default 180 - output_schema (object, required): map of attribute key → { type: "string"|"number"|"boolean", description }. Extracted answers come back under these exact keys; unknowns are omitted, never guessed. - schedule (object, optional) ### Contact schema - name (string, required) - phone (string, optional): E.164 format, e.g. +64211234567 — required for call/sms modes - email (string, optional): required for email mode - allowed_modes (("call"|"sms"|"email")[], required) - timezone (string, optional): IANA, e.g. Pacific/Auckland — used for local calling hours - country ("NZ"|"AU"|"US", optional) - custom_fields (object of string values, optional): carried through to results ### Example: quickstart in four calls 1. Create a project: ``` curl -X POST https://nosie.app/api/v1/projects \ -H "Authorization: Bearer nk_live_..." \ -H "Content-Type: application/json" \ -d '{ "name": "New-customer onboarding research", "brief": { "objective": "Understand why new customers signed up and where they stall in week one", "audience_description": "Admins who created an account in the last 14 days", "key_topics": ["previous tool", "reason for switching", "first-week friction"], "success_criteria": "Three specific friction points per customer", "identity_label": "the Acme Scheduling team", "allowed_modes": ["call", "email"], "timebox_seconds": 180, "output_schema": { "previous_tool": { "type": "string", "description": "What they used before" }, "switch_trigger": { "type": "string", "description": "The moment that made them switch" }, "team_size": { "type": "number", "description": "People who will use the product" } } } }' ``` 2. Add contacts (consent attestation mandatory): ``` curl -X POST https://nosie.app/api/v1/projects/PROJECT_ID/contacts \ -H "Authorization: Bearer nk_live_..." \ -H "Content-Type: application/json" \ -d '{ "contacts": [ { "name": "Rewi Morgan", "phone": "+64211234567", "email": "rewi@example.co.nz", "allowed_modes": ["call", "email"], "timezone": "Pacific/Auckland", "country": "NZ" } ], "consent": { "attested": true, "basis": "Ticked the research callback opt-in on our signup form", "method": "signup_form" } }' ``` 3. Launch: `curl -X POST https://nosie.app/api/v1/projects/PROJECT_ID/launch -H "Authorization: Bearer nk_live_..."` 4. Receive results on a webhook (below) or poll GET /v1/contacts/{id}/result. ## Webhooks Webhooks push results to your HTTPS endpoint as JSON POSTs, signed with HMAC-SHA256. Create them in the dashboard or via POST /v1/webhooks; the signing secret is returned once. Subscribing to no events means all events. ### Delivery envelope Every delivery: { "event": "", "created_at": "", "data": { ...event-specific } } Headers: Content-Type: application/json and X-Nosie-Signature. ### Events - contact.invited — invitation sent. data: contact_id, project_id, mode - contact.call_started — voice call began. data: contact_id, project_id, attempt_no - contact.completed — interview finished. data: contact_id, project_id, interview_id, summary, attributes (your output_schema keys), quality - contact.failed — attempts exhausted. data: contact_id, project_id, completion_status - contact.opted_out — contact opted out (permanent). data: contact_id, channel - project.completed — every contact in a project reached a terminal state - usage.recorded — billable completed interview recorded. data: interview_id, project_id ### Signature verification X-Nosie-Signature has the form `t=,v1=`, where v1 = HMAC-SHA256(secret, `${t}.${rawBody}`) as hex. Compute over the raw request body before JSON parsing. Reject stale timestamps (e.g. older than 5 minutes) to prevent replay, and compare with a timing-safe equality check. ```js import { createHmac, timingSafeEqual } from "node:crypto"; function verifyNosieSignature(header, rawBody, secret) { const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=", 2))); if (!t || !v1) return false; if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"); const a = Buffer.from(expected, "hex"); const b = Buffer.from(v1, "hex"); return a.length === b.length && timingSafeEqual(a, b); } ``` ### Retries & idempotency - Respond 2xx within 10 seconds; anything else counts as a failed attempt. Do slow work after acknowledging. - Failed deliveries retry with backoff, up to 5 attempts. - Delivery is at-least-once — key processing on interview_id / contact_id so duplicates are harmless. ## Results Every completed interview produces: a speaker-labelled transcript plus short summary; attributes mapped to the exact output_schema keys (unknowns omitted, never guessed); and quality signals (engagement, coverage, duration, outcome). Delivery: webhooks (push), REST (pull), or CSV/JSON export from the dashboard. ## Pricing NZ$20/month including 10 completed interviews, then NZ$2 per additional completed interview, billed monthly in arrears via Stripe. Voicemails, no-answers, failed attempts, and declines are never billed. Monthly spend cap available. Details: https://nosie.app/pricing ## Notes for AI agents - The user must create the API key themselves in the dashboard (Developers page) — keys are shown once and cannot be retrieved later. - Never fabricate a consent basis: a real human must be able to stand behind it. - Contact: hello@nosie.app · Ortomate Ltd., 12 Jessie Street, Wellington, New Zealand.