{"openapi":"3.1.0","info":{"title":"SurveyWave API","version":"1","description":"Contacts and audiences of one workspace. Authenticate with `Authorization: Bearer ep_live_…`; the key decides the workspace."},"servers":[{"url":"https://www.surveywave.io/api/v1"}],"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer"}},"schemas":{"Contact":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"},"firstName":{"type":["string","null"]},"lastName":{"$ref":"#/properties/firstName"},"mobile":{"type":["string","null"],"description":"E.164, e.g. +919876543210"},"whatsapp":{"type":["string","null"],"description":"E.164"},"city":{"$ref":"#/properties/firstName"},"state":{"$ref":"#/properties/firstName"},"country":{"type":["string","null"],"description":"ISO 3166-1 alpha-2"},"timezone":{"$ref":"#/properties/firstName"},"attributes":{"type":"object","additionalProperties":{"type":["string","number","boolean","null"]}},"status":{"type":"string","enum":["active","unsubscribed","bounced"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","email","firstName","lastName","mobile","whatsapp","city","state","country","timezone","attributes","status","createdAt","updatedAt"],"additionalProperties":false},"ContactInput":{"type":"object","properties":{"email":{"type":"string","maxLength":254},"firstName":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"lastName":{"anyOf":[{"$ref":"#/properties/firstName/anyOf/0"},{"type":"null"}]},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}]},"mobile":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"whatsapp":{"$ref":"#/properties/mobile"},"city":{"$ref":"#/properties/mobile"},"state":{"$ref":"#/properties/mobile"},"country":{"$ref":"#/properties/mobile"},"attributes":{"type":"object","additionalProperties":{"type":["string","number","boolean","null"]}},"subscribed":{"type":"boolean"},"audiences":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,32}$"},"maxItems":100},"remove":{"$ref":"#/properties/audiences/properties/add"}},"additionalProperties":false}},"additionalProperties":false},"Result":{"type":"object","properties":{"index":{"type":"integer"},"status":{"type":"string","enum":["created","updated","unchanged","rejected"]},"id":{"type":"string"},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["index","status"],"additionalProperties":false},"Audience":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["static","dynamic"]},"count":{"type":"integer"}},"required":["id","name","kind","count"],"additionalProperties":false},"Members":{"anyOf":[{"type":"object","properties":{"contactIds":{"type":"array","items":{"type":"string","maxLength":64},"minItems":1,"maxItems":1000}},"required":["contactIds"],"additionalProperties":false},{"type":"object","properties":{"emails":{"type":"array","items":{"type":"string","maxLength":254},"minItems":1,"maxItems":1000}},"required":["emails"],"additionalProperties":false}]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}},"responses":{"E400":{"description":"VALIDATION: The body or query is invalid; `details.fields` names the fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E401":{"description":"UNAUTHORIZED: The key is missing, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E402":{"description":"PLAN_LIMIT / PLAN_FEATURE: The plan has no API access, or a limit is reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403":{"description":"SCOPE / WORKSPACE_SUSPENDED: The key lacks the scope, or the workspace is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404":{"description":"NOT_FOUND: No such contact or audience in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E409":{"description":"CONFLICT / IDEMPOTENCY_MISMATCH / NOT_STATIC: The request conflicts with the data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E413":{"description":"TOO_LARGE: More than 100 contacts, or a body over 1 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E429":{"description":"RATE_LIMITED: Too many requests; wait `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/contacts":{"get":{"summary":"List contacts (oldest first, cursor pagination)","x-scope":"contacts:read","parameters":[{"name":"email","in":"query","required":false,"schema":{"type":"string","maxLength":254}},{"name":"audienceId","in":"query","required":false,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{8,32}$"}},{"name":"updatedSince","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"nextCursor":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}},"put":{"summary":"Upsert by email: one contact, or { contacts: [...≤100] }","x-scope":"contacts:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Replays the stored response for 24 hours; a different body → 409.","schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ContactInput"},{"type":"object","required":["contacts"],"properties":{"contacts":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/ContactInput"}}}}]}}}},"responses":{"200":{"description":"Per-record results (also when some are rejected)","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/Result"}}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"429":{"$ref":"#/components/responses/E429"}}}},"/contacts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"summary":"Get a contact","x-scope":"contacts:read","responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}},"patch":{"summary":"Update some fields (null clears one)","x-scope":"contacts:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Replays the stored response for 24 hours; a different body → 409.","schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInput"}}}},"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}}},"delete":{"summary":"Delete a contact (an opted-out email stays suppressed)","x-scope":"contacts:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Replays the stored response for 24 hours; a different body → 409.","schema":{"type":"string","maxLength":255}}],"responses":{"204":{"description":"Deleted"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}}},"/contacts/{id}/unsubscribe":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Unsubscribe (stops every channel)","x-scope":"contacts:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Replays the stored response for 24 hours; a different body → 409.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}}}},"/contacts/{id}/subscribe":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Re-subscribe (never a bounced contact → 409)","x-scope":"contacts:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Replays the stored response for 24 hours; a different body → 409.","schema":{"type":"string","maxLength":255}}],"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}}}},"/audiences":{"get":{"summary":"List audiences","x-scope":"contacts:read","responses":{"200":{"description":"Audiences","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Audience"}}}}}}},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"}}}},"/audiences/{id}/members":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"summary":"Add static members (≤ 1000 ids or emails)","x-scope":"contacts:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Replays the stored response for 24 hours; a different body → 409.","schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Members"}}}},"responses":{"200":{"description":"Counts","content":{"application/json":{"schema":{"type":"object","properties":{"added":{"type":"integer"},"notFound":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}}},"delete":{"summary":"Remove static members (≤ 1000 ids or emails)","x-scope":"contacts:write","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Replays the stored response for 24 hours; a different body → 409.","schema":{"type":"string","maxLength":255}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Members"}}}},"responses":{"200":{"description":"Counts","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"integer"},"notFound":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"}}}}}}