{"openapi":"3.1.1","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"Relay CRM API","version":"2026-10-12.3","description":"Versioned contact, local activity, notes, client brief and task-read contracts. Task lists preserve unpaged callers, provide stable explicit paging, and label Relay-only coverage and legacy dueDate instant semantics. Existing operations awaiting schema migration are listed in x-relay-legacy-operations. Contact timestamps are ISO instants or null when provider timestamps are invalid/missing. Contact pages use page/limit and are not a snapshot. Contact detail notes are capped at 50 with no cursor. Activities have separate cursor paging and explicit local-only coverage. Activity append and note append/edit/delete contracts supply an idempotent local write guarantee. Local-note deletion requires a 10-minute single-use actor-bound preview and BOTH contacts.write and contacts.read. Other legacy writes have no such guarantee or preview. Notes use separate cursor paging with a creation-time fence; content and revisions can change between pages."},"servers":[{"url":"/api/v1"}],"components":{"schemas":{"ApiError":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","properties":{"issues":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"code":{"type":"string"},"message":{"type":"string"}},"required":["path","code","message"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["issues"],"additionalProperties":false}},"required":["code","message"],"additionalProperties":{}}},"required":["error"],"additionalProperties":{}}},"securitySchemes":{"bearerKey":{"type":"http","scheme":"bearer","description":"Relay API key; never a browser session token. Write scope does not imply read scope."}}},"paths":{"/contacts":{"get":{"operationId":"contacts.list","summary":"List a page of contacts. Optional query, limit (1–100, default 20) and page (from 1, default 1). Prefer POST search for email or phone terms.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.read"],"x-relay-effect":"read","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":9007199254740991}}],"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address1":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string"}},"source":{"anyOf":[{"type":"string"},{"type":"null"}]},"assignedTo":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"updatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastActivity":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id","name","firstName","lastName","email","phone","address1","city","state","postalCode","country","tags","source","assignedTo","createdAt","updatedAt","lastActivity"],"additionalProperties":{}}},"total":{"type":"number"}},"required":["contacts","total"],"additionalProperties":{}},"example":{"contacts":[{"id":"synthetic-c1","name":"Jane Example","firstName":"Jane","lastName":"Example","email":"jane@example.invalid","phone":"+15555550101","address1":"123 Example Street","city":"Example City","state":"UT","postalCode":"84000","country":"US","tags":["buyer"],"source":"Synthetic open house","assignedTo":"synthetic-agent1","createdAt":"2026-10-01T12:00:00.000Z","updatedAt":"2026-10-09T12:00:00.000Z","lastActivity":"2026-10-09T12:00:00.000Z"}],"total":1}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/search":{"post":{"operationId":"contacts.search","summary":"Search contacts using a JSON body. Query is trimmed and must contain a non-whitespace character. Limit and page must be JSON numbers. This operation reads data.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.read"],"x-relay-effect":"read","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"query":{"type":"string","minLength":1,"pattern":"\\S","description":"Trimmed; requires at least one non-whitespace character."},"limit":{"type":"integer","minimum":1,"maximum":100},"page":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["query"]},"example":{"query":"jane@example.invalid","limit":20,"page":1}}}},"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address1":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string"}},"source":{"anyOf":[{"type":"string"},{"type":"null"}]},"assignedTo":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"updatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastActivity":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id","name","firstName","lastName","email","phone","address1","city","state","postalCode","country","tags","source","assignedTo","createdAt","updatedAt","lastActivity"],"additionalProperties":{}}},"total":{"type":"number"}},"required":["contacts","total"],"additionalProperties":{}},"example":{"contacts":[{"id":"synthetic-c1","name":"Jane Example","firstName":"Jane","lastName":"Example","email":"jane@example.invalid","phone":"+15555550101","address1":"123 Example Street","city":"Example City","state":"UT","postalCode":"84000","country":"US","tags":["buyer"],"source":"Synthetic open house","assignedTo":"synthetic-agent1","createdAt":"2026-10-01T12:00:00.000Z","updatedAt":"2026-10-09T12:00:00.000Z","lastActivity":"2026-10-09T12:00:00.000Z"}],"total":1}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/{id}":{"get":{"operationId":"contacts.get","summary":"Read one contact and its latest 50 Relay notes, newest first. Notes are a bounded subset; this endpoint has no note cursor.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.read"],"x-relay-effect":"read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address1":{"anyOf":[{"type":"string"},{"type":"null"}]},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"postalCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string"}},"source":{"anyOf":[{"type":"string"},{"type":"null"}]},"assignedTo":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"updatedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastActivity":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"notes":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"authorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","body","authorName","createdAt"],"additionalProperties":{}}}},"required":["id","name","firstName","lastName","email","phone","address1","city","state","postalCode","country","tags","source","assignedTo","createdAt","updatedAt","lastActivity","notes"],"additionalProperties":{}},"example":{"id":"synthetic-c1","name":"Jane Example","firstName":"Jane","lastName":"Example","email":"jane@example.invalid","phone":"+15555550101","address1":"123 Example Street","city":"Example City","state":"UT","postalCode":"84000","country":"US","tags":["buyer"],"source":"Synthetic open house","assignedTo":"synthetic-agent1","createdAt":"2026-10-01T12:00:00.000Z","updatedAt":"2026-10-09T12:00:00.000Z","lastActivity":"2026-10-09T12:00:00.000Z","notes":[{"id":"synthetic-n1","body":"Synthetic introduction note","authorName":"Alex Example","createdAt":"2026-10-09T12:00:00.000Z"}]}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/{id}/activities":{"get":{"operationId":"contacts.activities.list","summary":"List explicit Relay-local activity, newest occurred-at first. Limit 1–100 (default 20); follow nextCursor until null. The cursor bounds creation time and belongs to this account/contact. Local-only coverage is not evidence that no upstream conversation occurred. Cancelled meetings affect neither communication nor unsuccessful-attempt recency.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.read"],"x-relay-effect":"read","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":1000}},{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}}],"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"activities":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"contactId":{"type":"string"},"channel":{"type":"string","enum":["call","meeting","email","sms"]},"outcome":{"type":"string","enum":["connected","no_answer","left_voicemail","held","no_show","cancelled","sent","received"]},"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"actorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"string","enum":["relay_ui","relay_api"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"isCommunication":{"type":"boolean"}},"required":["id","contactId","channel","outcome","occurredAt","note","actorName","source","createdAt","isCommunication"],"additionalProperties":{}}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]},"asOf":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"coverage":{"type":"string","const":"relay_local_only"},"lastCommunicationAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastUnsuccessfulAttemptAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["activities","nextCursor","asOf","coverage","lastCommunicationAt","lastUnsuccessfulAttemptAt"],"additionalProperties":{}},"example":{"activities":[{"id":"synthetic-activity1","contactId":"synthetic-c1","channel":"call","outcome":"no_answer","occurredAt":"2026-10-09T12:00:00.000Z","note":"Synthetic call attempt","actorName":"Alex Example","source":"relay_api","createdAt":"2026-10-09T12:05:00.000Z","isCommunication":false}],"nextCursor":null,"asOf":"2026-10-09T12:10:00.000Z","coverage":"relay_local_only","lastCommunicationAt":null,"lastUnsuccessfulAttemptAt":"2026-10-09T12:00:00.000Z"}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"contacts.activities.append","summary":"Explicitly log an already occurred call, meeting, email or SMS. Required Idempotency-Key: 8–200 ASCII letters/digits or . _ : -. Same actor/account/key and normalized request replay one atomic local append; changed input returns 409. Future times are rejected. Actor/source are server assigned; no outreach is sent and nothing is mirrored. Response retained 7 days, then 410 includes original operation/result IDs and never executes again. Recheck authorization/contact ownership on every replay.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.write"],"x-relay-effect":"write","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Reuse the same key and normalized request for an uncertain save. Keys never expire into permission to execute again.","schema":{"type":"string","minLength":8,"maxLength":200,"pattern":"^[A-Za-z0-9._:-]+$"},"example":"synthetic-operation-request-1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"note":{"type":"string","maxLength":5000,"pattern":"^[^\\u0000]*$"},"channel":{"type":"string","const":"call"},"outcome":{"type":"string","enum":["connected","no_answer","left_voicemail"]}},"required":["occurredAt","channel","outcome"],"additionalProperties":false},{"type":"object","properties":{"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"note":{"type":"string","maxLength":5000,"pattern":"^[^\\u0000]*$"},"channel":{"type":"string","const":"meeting"},"outcome":{"type":"string","enum":["held","no_show","cancelled"]}},"required":["occurredAt","channel","outcome"],"additionalProperties":false},{"type":"object","properties":{"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"note":{"type":"string","maxLength":5000,"pattern":"^[^\\u0000]*$"},"channel":{"type":"string","const":"email"},"outcome":{"type":"string","enum":["sent","received"]}},"required":["occurredAt","channel","outcome"],"additionalProperties":false},{"type":"object","properties":{"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"note":{"type":"string","maxLength":5000,"pattern":"^[^\\u0000]*$"},"channel":{"type":"string","const":"sms"},"outcome":{"type":"string","enum":["sent","received"]}},"required":["occurredAt","channel","outcome"],"additionalProperties":false}]},"example":{"channel":"call","outcome":"no_answer","occurredAt":"2026-10-09T12:00:00.000Z","note":"Synthetic call attempt"}}}},"responses":{"201":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"activity":{"type":"object","properties":{"id":{"type":"string"},"contactId":{"type":"string"},"channel":{"type":"string","enum":["call","meeting","email","sms"]},"outcome":{"type":"string","enum":["connected","no_answer","left_voicemail","held","no_show","cancelled","sent","received"]},"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"actorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"string","enum":["relay_ui","relay_api"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"isCommunication":{"type":"boolean"}},"required":["id","contactId","channel","outcome","occurredAt","note","actorName","source","createdAt","isCommunication"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean"},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":false},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["activity","operation"],"additionalProperties":{}},"example":{"activity":{"id":"synthetic-activity1","contactId":"synthetic-c1","channel":"call","outcome":"no_answer","occurredAt":"2026-10-09T12:00:00.000Z","note":"Synthetic call attempt","actorName":"Alex Example","source":"relay_api","createdAt":"2026-10-09T12:05:00.000Z","isCommunication":false},"operation":{"id":"synthetic-op1","status":"succeeded","replayed":false,"resultIds":["synthetic-activity1"],"responseExpired":false,"replayUntil":"2026-10-16T12:05:00.000Z"}}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency-Key already used with different input.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"410":{"description":"Original write succeeded, but retained response expired. Operation/result IDs remain; do not execute with a new key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","properties":{"issues":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"code":{"type":"string"},"message":{"type":"string"}},"required":["path","code","message"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["issues"],"additionalProperties":false}},"required":["code","message"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean","const":true},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":true},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["error","operation"],"additionalProperties":{}}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/{id}/notes":{"get":{"operationId":"contacts.notes.list","summary":"List Relay-local notes, created-at descending then ID descending. Limit 1–100 (default 20); follow nextCursor until null. Cursor belongs to this account/contact and fences creation time. Contents can change between pages; this is not a snapshot. Original author/source and current revision are returned; legacy attribution may be unknown.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.read"],"x-relay-effect":"read","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":1000}},{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}}],"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"notes":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"authorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revision":{"type":"integer","minimum":1,"maximum":9007199254740991},"source":{"type":"string","enum":["relay_ui","relay_api","relay_legacy"]}},"required":["id","body","authorName","createdAt","updatedAt","revision","source"],"additionalProperties":{}}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]},"asOf":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"coverage":{"type":"string","const":"relay_local_only"}},"required":["notes","nextCursor","asOf","coverage"],"additionalProperties":{}},"example":{"notes":[{"id":"synthetic-note1","body":"Synthetic open house introduction","authorName":"API key: Example agent","createdAt":"2026-10-10T00:00:00.000Z","updatedAt":"2026-10-10T00:00:00.000Z","revision":1,"source":"relay_api"}],"nextCursor":null,"asOf":"2026-10-10T00:05:00.000Z","coverage":"relay_local_only"}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"operationId":"contacts.notes.append","summary":"Append a nonempty trimmed note of at most 10,000 characters. Author/source are assigned by the server. Required Idempotency-Key: 8–200 ASCII letters/digits or . _ : -. Reuse the same actor/account/key and normalized request after an uncertain save; changed input returns 409. Local write and receipt commit atomically. Receipt body retained 7 days; then 410 retains operation/result IDs and never executes again. Current scope/contact ownership is checked before every replay. No outreach, CRM mirror or activity log is created.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.write"],"x-relay-effect":"write","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Reuse the same key and normalized request for an uncertain save. Keys never expire into permission to execute again.","schema":{"type":"string","minLength":8,"maxLength":200,"pattern":"^[A-Za-z0-9._:-]+$"},"example":"synthetic-operation-request-1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000,"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"}},"required":["body"],"additionalProperties":false},"example":{"body":"Synthetic open house introduction"}}}},"responses":{"201":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"note":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"authorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revision":{"type":"integer","minimum":1,"maximum":9007199254740991},"source":{"type":"string","enum":["relay_ui","relay_api","relay_legacy"]}},"required":["id","body","authorName","createdAt","updatedAt","revision","source"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean"},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":false},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["note","operation"],"additionalProperties":{}},"example":{"note":{"id":"synthetic-note1","body":"Synthetic open house introduction","authorName":"API key: Example agent","createdAt":"2026-10-10T00:00:00.000Z","updatedAt":"2026-10-10T00:00:00.000Z","revision":1,"source":"relay_api"},"operation":{"id":"synthetic-operation1","status":"succeeded","replayed":false,"resultIds":["synthetic-note1"],"responseExpired":false,"replayUntil":"2026-10-17T00:00:00.000Z"}}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency-Key already used with different input.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"410":{"description":"Original write succeeded, but retained response expired. Operation/result IDs remain; do not execute with a new key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","properties":{"issues":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"code":{"type":"string"},"message":{"type":"string"}},"required":["path","code","message"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["issues"],"additionalProperties":false}},"required":["code","message"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean","const":true},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":true},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["error","operation"],"additionalProperties":{}}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/{id}/notes/{noteId}":{"patch":{"operationId":"contacts.notes.edit","summary":"Edit a note using its last-read integer revision. Stale revision returns 409 note_revision_conflict; re-read and resolve the draft before making a new request. Every successful edit increments revision and preserves original author/source. Replay returns the original edit result even if the note later changes. Missing/wrong-parent notes return 404. Required Idempotency-Key: 8–200 ASCII letters/digits or . _ : -. Reuse the same actor/account/key and normalized request after an uncertain save; changed input returns 409. Local write and receipt commit atomically. Receipt body retained 7 days; then 410 retains operation/result IDs and never executes again. Current scope/contact ownership is checked before every replay. No outreach, CRM mirror or activity log is created.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.write"],"x-relay-effect":"write","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"noteId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Reuse the same key and normalized request for an uncertain save. Keys never expire into permission to execute again.","schema":{"type":"string","minLength":8,"maxLength":200,"pattern":"^[A-Za-z0-9._:-]+$"},"example":"synthetic-operation-request-1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000,"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"},"revision":{"type":"integer","minimum":1,"maximum":2147483646}},"required":["body","revision"],"additionalProperties":false},"example":{"body":"Synthetic updated context","revision":1}}}},"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"note":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"authorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revision":{"type":"integer","minimum":1,"maximum":9007199254740991},"source":{"type":"string","enum":["relay_ui","relay_api","relay_legacy"]}},"required":["id","body","authorName","createdAt","updatedAt","revision","source"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean"},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":false},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["note","operation"],"additionalProperties":{}},"example":{"note":{"id":"synthetic-note1","body":"Synthetic updated context","authorName":"API key: Example agent","createdAt":"2026-10-10T00:00:00.000Z","updatedAt":"2026-10-10T00:00:00.000Z","revision":2,"source":"relay_api"},"operation":{"id":"synthetic-operation1","status":"succeeded","replayed":false,"resultIds":["synthetic-note1"],"responseExpired":false,"replayUntil":"2026-10-17T00:00:00.000Z"}}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency-Key already used with different input, or note revision changed (note_revision_conflict).","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"410":{"description":"Original write succeeded, but retained response expired. Operation/result IDs remain; do not execute with a new key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","properties":{"issues":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"code":{"type":"string"},"message":{"type":"string"}},"required":["path","code","message"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["issues"],"additionalProperties":false}},"required":["code","message"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean","const":true},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":true},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["error","operation"],"additionalProperties":{}}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"delete":{"operationId":"contacts.notes.delete","summary":"Permanently delete the note reviewed in preview-delete. Requires BOTH contacts.write and contacts.read, its previewToken, and Idempotency-Key. A changed note or unavailable/expired/used approval returns 409 action_preview_invalid; missing/wrong-parent note returns 404. Approval consumption, note deletion and receipt commit together. Retry the EXACT same key/token/request after an uncertain response, even if the token expired or note is already gone. Do not substitute a fresh preview/key for an uncertain deletion. Saved response retained 7 days, then 410 retains original operation/deleted-note IDs and never executes again. Fresh scopes/contact ownership checked on every request/replay. No GHL mutation, message, activity log or queue is created.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.write","contacts.read"],"x-relay-effect":"destructive","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"noteId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Reuse the same key and normalized request for an uncertain save. Keys never expire into permission to execute again.","schema":{"type":"string","minLength":8,"maxLength":200,"pattern":"^[A-Za-z0-9._:-]+$"},"example":"synthetic-operation-request-1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"previewToken":{"type":"string","minLength":80,"maxLength":80,"pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.[A-Za-z0-9_-]{43}$"}},"required":["previewToken"],"additionalProperties":false},"example":{"previewToken":"00000000-0000-4000-8000-000000000000.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}}}},"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"deletedNoteId":{"type":"string"},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean"},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":false},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["deletedNoteId","operation"],"additionalProperties":{}},"example":{"deletedNoteId":"synthetic-note1","operation":{"id":"synthetic-operation1","status":"succeeded","replayed":false,"resultIds":["synthetic-note1"],"responseExpired":false,"replayUntil":"2026-10-17T00:00:00.000Z"}}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Idempotency-Key already used with different input, or approval unavailable/expired/used/target changed (action_preview_invalid).","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"410":{"description":"Original write succeeded, but retained response expired. Operation/result IDs remain; do not execute with a new key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","properties":{"issues":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"code":{"type":"string"},"message":{"type":"string"}},"required":["path","code","message"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["issues"],"additionalProperties":false}},"required":["code","message"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean","const":true},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":true},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["error","operation"],"additionalProperties":{}}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/{id}/notes/{noteId}/preview-delete":{"post":{"operationId":"contacts.notes.previewDelete","summary":"Preview permanent deletion of one Relay-local note. Requires BOTH contacts.write and contacts.read. Returns its original author, revision and body (first 10,000 characters for oversized legacy notes, with bodyLength/bodyTruncated disclosure). No note is changed. The opaque approval token binds this account/actor/contact/note and full note content/revision, expires in 10 minutes and can execute once. Store it privately. Requesting another preview is safe and issues a distinct token.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.write","contacts.read"],"x-relay-effect":"preview","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"noteId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false},"example":{}}}},"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"preview":{"type":"object","properties":{"token":{"type":"string","minLength":80,"maxLength":80,"pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\.[A-Za-z0-9_-]{43}$"},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"summary":{"type":"object","properties":{"action":{"type":"string","const":"delete_note"},"permanent":{"type":"boolean","const":true},"coverage":{"type":"string","const":"relay_local_only"},"note":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string","maxLength":10000},"authorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revision":{"type":"integer","minimum":1,"maximum":9007199254740991},"source":{"type":"string","enum":["relay_ui","relay_api","relay_legacy"]},"bodyLength":{"type":"integer","minimum":0,"maximum":9007199254740991},"bodyTruncated":{"type":"boolean"}},"required":["id","body","authorName","createdAt","updatedAt","revision","source","bodyLength","bodyTruncated"],"additionalProperties":{}}},"required":["action","permanent","coverage","note"],"additionalProperties":{}}},"required":["token","expiresAt","summary"],"additionalProperties":{}}},"required":["preview"],"additionalProperties":{}},"example":{"preview":{"token":"00000000-0000-4000-8000-000000000000.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","expiresAt":"2026-10-10T00:10:00.000Z","summary":{"action":"delete_note","permanent":true,"coverage":"relay_local_only","note":{"id":"synthetic-note1","body":"Synthetic open house introduction","authorName":"API key: Example agent","createdAt":"2026-10-10T00:00:00.000Z","updatedAt":"2026-10-10T00:00:00.000Z","revision":1,"source":"relay_api","bodyLength":33,"bodyTruncated":false}}}}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/{id}/profile":{"get":{"operationId":"contacts.profile.get","summary":"Read the optional structured client brief saved in Relay, independent of upstream identity/address fields. A successfully read absent brief is profile:null; failure is an error, never absence. Role, timeframe, budget range, currency, areas and channel are preferences; channel does not grant communication consent. Current raw contact ownership is verified before the local read.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.read"],"x-relay-effect":"read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}}],"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"profile":{"anyOf":[{"type":"object","properties":{"role":{"anyOf":[{"type":"string","enum":["buyer","seller","both"]},{"type":"null"}]},"timeframe":{"anyOf":[{"type":"string","minLength":1,"maxLength":200,"allOf":[{"pattern":"\\S"},{"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"},{"pattern":"^(?:[^\\uD800-\\uDFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])*$"}]},{"type":"null"}]},"budgetMin":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000000,"multipleOf":0.01},{"type":"null"}]},"budgetMax":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000000,"multipleOf":0.01},{"type":"null"}]},"currency":{"type":"string","enum":["AED","AFN","ALL","AMD","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BHD","BIF","BMD","BND","BOB","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHF","CLP","CNY","COP","CRC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","UYU","UZS","VED","VES","VND","VUV","WST","XAF","XCD","XCG","XOF","XPF","YER","ZAR","ZMW","ZWG"]},"areas":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"allOf":[{"pattern":"\\S"},{"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"},{"pattern":"^(?:[^\\uD800-\\uDFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])*$"}]},"uniqueItems":true},"preferredChannel":{"anyOf":[{"type":"string","enum":["email","sms","call"]},{"type":"null"}]},"id":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"},"contactId":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"},"revision":{"type":"integer","minimum":1,"maximum":2147483647},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["role","timeframe","budgetMin","budgetMax","currency","areas","preferredChannel","id","contactId","revision","createdAt","updatedAt"],"additionalProperties":{}},{"type":"null"}]},"coverage":{"type":"string","const":"relay_local_only"}},"required":["profile","coverage"],"additionalProperties":{}},"example":{"profile":{"id":"synthetic-profile1","contactId":"synthetic-c1","role":"buyer","timeframe":"Within three months","budgetMin":350000,"budgetMax":500000,"currency":"USD","areas":["Example City","Example District"],"preferredChannel":"sms","revision":1,"createdAt":"2026-10-12T00:00:00.000Z","updatedAt":"2026-10-12T00:00:00.000Z"},"coverage":"relay_local_only"}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"patch":{"operationId":"contacts.profile.update","summary":"Requires BOTH contacts.write and contacts.read because the response contains the full effective brief. Send original revision (0 only when no brief exists) and at least one changed field. Omission preserves, null clears nullable fields, [] clears areas. Budgets are nonnegative JSON numbers up to 1 trillion with at most two decimals; the effective minimum cannot exceed maximum, including one-sided updates. Currency is an uppercase supported current ISO currency code, default USD on first creation; changing it relabels amounts without conversion. Areas are trimmed, at most 20 names of 100 characters; duplicate names ignoring case are invalid. A stale revision returns 409; review current values before a new request. Required Idempotency-Key is 8–200 ASCII letters/digits or . _ : -. Reuse the exact actor/account/key/request after an interrupted save. Update and receipt commit atomically; replay returns the original result even after later changes. Response body retained 7 days, then 410 retains operation/profile IDs and never executes again. Fresh scope/contact access checked before every replay. No upstream mutation, message, task, activity or queue is created.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.write","contacts.read"],"x-relay-effect":"write","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Reuse the same key and normalized request for an uncertain save. Keys never expire into permission to execute again.","schema":{"type":"string","minLength":8,"maxLength":200,"pattern":"^[A-Za-z0-9._:-]+$"},"example":"synthetic-operation-request-1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"revision":{"type":"integer","minimum":0,"maximum":2147483646},"role":{"anyOf":[{"type":"string","enum":["buyer","seller","both"]},{"type":"null"}]},"timeframe":{"anyOf":[{"type":"string","minLength":1,"maxLength":200,"allOf":[{"pattern":"\\S"},{"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"},{"pattern":"^(?:[^\\uD800-\\uDFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])*$"}]},{"type":"null"}]},"budgetMin":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000000,"multipleOf":0.01},{"type":"null"}]},"budgetMax":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000000,"multipleOf":0.01},{"type":"null"}]},"currency":{"type":"string","enum":["AED","AFN","ALL","AMD","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BHD","BIF","BMD","BND","BOB","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHF","CLP","CNY","COP","CRC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","UYU","UZS","VED","VES","VND","VUV","WST","XAF","XCD","XCG","XOF","XPF","YER","ZAR","ZMW","ZWG"]},"areas":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"allOf":[{"pattern":"\\S"},{"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"},{"pattern":"^(?:[^\\uD800-\\uDFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])*$"}]},"uniqueItems":true},"preferredChannel":{"anyOf":[{"type":"string","enum":["email","sms","call"]},{"type":"null"}]}},"required":["revision"],"additionalProperties":false,"minProperties":2},"example":{"revision":0,"role":"buyer","budgetMin":350000,"budgetMax":500000,"currency":"USD"}}}},"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"profile":{"type":"object","properties":{"role":{"anyOf":[{"type":"string","enum":["buyer","seller","both"]},{"type":"null"}]},"timeframe":{"anyOf":[{"type":"string","minLength":1,"maxLength":200,"allOf":[{"pattern":"\\S"},{"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"},{"pattern":"^(?:[^\\uD800-\\uDFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])*$"}]},{"type":"null"}]},"budgetMin":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000000,"multipleOf":0.01},{"type":"null"}]},"budgetMax":{"anyOf":[{"type":"number","minimum":0,"maximum":1000000000000,"multipleOf":0.01},{"type":"null"}]},"currency":{"type":"string","enum":["AED","AFN","ALL","AMD","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BHD","BIF","BMD","BND","BOB","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHF","CLP","CNY","COP","CRC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","UYU","UZS","VED","VES","VND","VUV","WST","XAF","XCD","XCG","XOF","XPF","YER","ZAR","ZMW","ZWG"]},"areas":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"allOf":[{"pattern":"\\S"},{"pattern":"^[^\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f]*$"},{"pattern":"^(?:[^\\uD800-\\uDFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])*$"}]},"uniqueItems":true},"preferredChannel":{"anyOf":[{"type":"string","enum":["email","sms","call"]},{"type":"null"}]},"id":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"},"contactId":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"},"revision":{"type":"integer","minimum":1,"maximum":2147483647},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["role","timeframe","budgetMin","budgetMax","currency","areas","preferredChannel","id","contactId","revision","createdAt","updatedAt"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean"},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":false},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["profile","operation"],"additionalProperties":{}},"example":{"profile":{"id":"synthetic-profile1","contactId":"synthetic-c1","role":"buyer","timeframe":"Within three months","budgetMin":350000,"budgetMax":500000,"currency":"USD","areas":["Example City","Example District"],"preferredChannel":"sms","revision":1,"createdAt":"2026-10-12T00:00:00.000Z","updatedAt":"2026-10-12T00:00:00.000Z"},"operation":{"id":"synthetic-operation1","status":"succeeded","replayed":false,"resultIds":["synthetic-profile1"],"responseExpired":false,"replayUntil":"2026-10-19T00:00:00.000Z"}}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Original saved revision changed (profile_revision_conflict), or Idempotency-Key already used with different normalized input.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"410":{"description":"Original write succeeded, but retained response expired. Operation/result IDs remain; do not execute with a new key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","properties":{"issues":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"code":{"type":"string"},"message":{"type":"string"}},"required":["path","code","message"],"additionalProperties":false}},"truncated":{"type":"boolean"}},"required":["issues"],"additionalProperties":false}},"required":["code","message"],"additionalProperties":{}},"operation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","const":"succeeded"},"replayed":{"type":"boolean","const":true},"resultIds":{"minItems":1,"maxItems":1,"type":"array","items":{"type":"string"}},"responseExpired":{"type":"boolean","const":true},"replayUntil":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","status","replayed","resultIds","responseExpired","replayUntil"],"additionalProperties":{}}},"required":["error","operation"],"additionalProperties":{}}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/tasks":{"get":{"operationId":"tasks.list","summary":"List Relay-local tasks. Filter status (including open = pending/in_progress), contactId, dealId, assignedUserId; compatible ghlContactId/ghlOpportunityId aliases must agree. Contact and deal filters combine with AND; no parent metadata is read. dueFrom is inclusive and dueBefore exclusive, using explicit-offset timestamps against legacy dueDate instants; null dates are excluded from a range. No calendar-day meaning is inferred. Supply each recognized parameter once. Unknown parameters are ignored. Limit 1–100 enables database paging; omitting limit returns all matching tasks and ignores page for compatibility. Stable order: dueDate ascending (nulls last), priority descending, id ascending. Count and rows agree within a response; pages across requests are not a snapshot. asOf is read-completion time. Partner-minted keys retain their restricted vendor-neutral projection. Read coverage excludes remote-only tasks.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["tasks.read"],"x-relay-effect":"read","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","in_progress","completed","cancelled","open"]}},{"name":"contactId","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]+$"}},{"name":"ghlContactId","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]+$"}},{"name":"dealId","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]+$"}},{"name":"ghlOpportunityId","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]+$"}},{"name":"assignedUserId","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]+$"}},{"name":"dueFrom","in":"query","required":false,"schema":{"type":"string","maxLength":40,"format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"dueBefore","in":"query","required":false,"schema":{"type":"string","maxLength":40,"format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":2147483647}}],"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","oneOf":[{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"paging":{"type":"object","properties":{"limit":{"anyOf":[{"type":"integer","minimum":1,"maximum":100},{"type":"null"}]},"page":{"type":"integer","minimum":1,"maximum":9007199254740991},"hasMore":{"type":"boolean"}},"required":["limit","page","hasMore"],"additionalProperties":false},"coverage":{"type":"string","const":"relay_local_only"},"dateSemantics":{"type":"string","const":"legacy_dueDate_instant"},"asOf":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"projection":{"type":"string","const":"standard"},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string","enum":["pending","in_progress","completed","cancelled"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"dueDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"tenantId":{"type":"string"},"assignedUserId":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"ghlContactId":{"anyOf":[{"type":"string"},{"type":"null"}]},"ghlOpportunityId":{"anyOf":[{"type":"string"},{"type":"null"}]},"ghlTaskId":{"anyOf":[{"type":"string"},{"type":"null"}]},"completedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"completionNotes":{"anyOf":[{"type":"string"},{"type":"null"}]},"taskPlanId":{"anyOf":[{"type":"string"},{"type":"null"}]},"taskPlanItemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"taskInstanceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","title","status","priority","dueDate","tenantId","assignedUserId","description","ghlContactId","ghlOpportunityId","ghlTaskId","completedAt","completionNotes","taskPlanId","taskPlanItemId","taskInstanceId","createdAt","updatedAt"],"additionalProperties":{}}}},"required":["total","paging","coverage","dateSemantics","asOf","projection","tasks"],"additionalProperties":false},{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"paging":{"type":"object","properties":{"limit":{"anyOf":[{"type":"integer","minimum":1,"maximum":100},{"type":"null"}]},"page":{"type":"integer","minimum":1,"maximum":9007199254740991},"hasMore":{"type":"boolean"}},"required":["limit","page","hasMore"],"additionalProperties":false},"coverage":{"type":"string","const":"relay_local_only"},"dateSemantics":{"type":"string","const":"legacy_dueDate_instant"},"asOf":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"projection":{"type":"string","const":"partner"},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string","enum":["pending","in_progress","completed","cancelled"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"dueDate":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"contactId":{"anyOf":[{"type":"string"},{"type":"null"}]},"opportunityId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","title","status","priority","dueDate","contactId","opportunityId"],"additionalProperties":false}}},"required":["total","paging","coverage","dateSemantics","asOf","projection","tasks"],"additionalProperties":false}]},"example":{"tasks":[{"id":"synthetic-task-1","tenantId":"synthetic-account","assignedUserId":"synthetic-user","title":"Call Jane","description":"Synthetic follow-up","status":"pending","priority":"high","dueDate":"2026-10-16T16:00:00.000Z","ghlContactId":"synthetic-contact","ghlOpportunityId":null,"ghlTaskId":null,"completedAt":null,"completionNotes":null,"taskPlanId":null,"taskPlanItemId":null,"taskInstanceId":null,"createdAt":"2026-10-12T12:00:00.000Z","updatedAt":"2026-10-12T12:00:00.000Z"}],"total":1,"projection":"standard","paging":{"limit":20,"page":1,"hasMore":false},"coverage":"relay_local_only","dateSemantics":"legacy_dueDate_instant","asOf":"2026-10-12T12:00:00.000Z"}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/contacts/cleanup":{"get":{"operationId":"contacts.cleanup","summary":"Review missing usable contact details and possible duplicate contacts without changing records. Exact normalized email/full phone-digit matches are stronger cues than same names; country/reachability/consent are not inferred. Shared details may be intentional. Groups with identical members combine their reasons. At most 20 members are displayed per group; memberTotal/memberTruncated describe the rest. Counts cover loaded contacts only, and partial reads never prove no other issues exist. Limit 1–100 (default20); kind all/missing_details/duplicates; follow nextCursor with the same kind/limit. A changed input fingerprint returns409 cleanup_changed; restart the review. fresh1 bypasses cached contact data. computedAt is evaluation time, not a provider snapshot timestamp. API keys remain freshly checked during the bounded read. No notes/tasks/deals/profile data, writes, merge or outreach.","security":[{"bearerKey":[]}],"x-relay-required-scopes":["contacts.read"],"x-relay-effect":"read","parameters":[{"name":"kind","in":"query","required":false,"schema":{"default":"all","type":"string","enum":["all","missing_details","duplicates"]}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":2048,"pattern":"^[A-Za-z0-9_-]+$"}},{"name":"fresh","in":"query","required":false,"schema":{"default":"0","type":"string","enum":["0","1"]}}],"responses":{"200":{"description":"Successful operation. Additional response fields may be added compatibly.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"findings":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^cleanup-[a-f0-9]{64}$"},"kind":{"type":"string","enum":["missing_details","possible_duplicate"]},"reasons":{"minItems":1,"maxItems":3,"type":"array","items":{"type":"string","enum":["missing_email","missing_phone","same_email","same_phone","same_name"]}},"strength":{"type":"string","enum":["missing_details","shared_details","same_name_only"]},"contacts":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[A-Za-z0-9_-]+$"},"name":{"type":"string","maxLength":500},"email":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]}},"required":["id","name","email","phone"],"additionalProperties":false}},"memberTotal":{"type":"integer","minimum":1,"maximum":5000},"memberTruncated":{"type":"boolean"}},"required":["id","kind","reasons","strength","contacts","memberTotal","memberTruncated"],"additionalProperties":false}},"total":{"type":"integer","minimum":0,"maximum":20000},"summary":{"type":"object","properties":{"contactsRead":{"type":"integer","minimum":0,"maximum":5000},"missingEmail":{"type":"integer","minimum":0,"maximum":5000},"missingPhone":{"type":"integer","minimum":0,"maximum":5000},"duplicateGroups":{"type":"integer","minimum":0,"maximum":15000}},"required":["contactsRead","missingEmail","missingPhone","duplicateGroups"],"additionalProperties":false},"coverage":{"type":"string","const":"crm_contact_book"},"sourceStatus":{"type":"string","enum":["complete","partial"]},"sourceFreshness":{"type":"string","enum":["fresh_read","may_be_cached"]},"computedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"nextCursor":{"anyOf":[{"type":"string","minLength":1,"maxLength":2048,"pattern":"^[A-Za-z0-9_-]+$"},{"type":"null"}]}},"required":["findings","total","summary","coverage","sourceStatus","sourceFreshness","computedAt","fingerprint","nextCursor"],"additionalProperties":false},"example":{"findings":[{"id":"cleanup-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","kind":"missing_details","reasons":["missing_phone"],"strength":"missing_details","contacts":[{"id":"synthetic-c1","name":"Jane Example","email":"jane@example.invalid","phone":null}],"memberTotal":1,"memberTruncated":false}],"total":1,"summary":{"contactsRead":1,"missingEmail":0,"missingPhone":1,"duplicateGroups":0},"coverage":"crm_contact_book","sourceStatus":"complete","sourceFreshness":"fresh_read","computedAt":"2026-10-12T12:00:00.000Z","fingerprint":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","nextCursor":null}}}},"400":{"description":"Invalid request or malformed JSON; an upstream error may also use this status.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing, invalid, expired or revoked key.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Required scope missing, or upstream access denied.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Contact unavailable in the account, including upstream not-found responses.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"408":{"description":"Request cancelled during contact review; no record changed.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Contact inputs changed; discard the cursor and restart the review.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Relay key rate limit, or upstream rate limit.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}},"Retry-After":{"description":"60 seconds for Relay's per-key limit; not guaranteed for upstream 429 responses.","schema":{"type":"string"},"example":"60"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Unexpected failure; report X-Request-Id.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Current membership or CRM connection could not be verified.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"default":{"description":"Upstream errors may forward their HTTP status with code upstream_error.","headers":{"X-Request-Id":{"description":"Server-generated troubleshooting ID.","schema":{"type":"string","format":"uuid"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"x-relay-contract-changelog":[{"version":"2026-10-12.3","summary":"Read-only contact cleanup review: missing usable details, possible duplicates, bounded groups and truthful partial coverage with fingerprint-bound paging."},{"version":"2026-10-12.2","summary":"Scoped Relay task reads: contact/deal/open status/assignee and explicit timestamp filters, stable database paging and totals, compatible unpaged callers and partner projection."},{"version":"2026-10-12.1","summary":"Structured Relay client brief: scoped reads and idempotent revision-checked partial updates, explicit combined read/write access, budget/currency and clear semantics."},{"version":"2026-10-10.3","summary":"Actor-bound, expiring previews and idempotent permanent local-note deletion; explicit combined read/write scopes."},{"version":"2026-10-10.2","summary":"Paged notes, persistent attribution and idempotent append/revision-checked edit."},{"version":"2026-10-10.1","summary":"Explicit local activity reads and idempotent append, with coverage and replay semantics."},{"version":"2026-10-09.1","summary":"Generated contact read contracts and error envelopes; remaining operations explicitly inventoried as legacy."}],"x-relay-legacy-operations":[{"method":"POST","path":"/contacts","scope":"contacts.write","summary":"Create a contact","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"PUT","path":"/contacts/:id","scope":"contacts.write","summary":"Update a contact","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"DELETE","path":"/contacts/:id","scope":"contacts.write","summary":"Delete a contact (permanent, removed from GHL too)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"POST","path":"/tasks","scope":"tasks.write","summary":"Create a task (title required; contact/opportunity links and assignee optional, defaults to key owner; unlinked tasks remain local to Relay)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/tasks/:id","scope":"tasks.read","summary":"Get a task","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"PUT","path":"/tasks/:id","scope":"tasks.write","summary":"Update a task (edits and completions mirror to GHL when the task is contact-linked)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"DELETE","path":"/tasks/:id","scope":"tasks.write","summary":"Delete a task (mirrors to GHL when contact-linked)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/pipeline/stages","scope":"pipeline.read","summary":"List pipelines and stages","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/pipeline/opportunities","scope":"pipeline.read","summary":"List opportunities","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"POST","path":"/pipeline/opportunities","scope":"pipeline.write","summary":"Create an opportunity (name/pipelineId/pipelineStageId required; contactId optional — omitting it provisions a contact from the deal name; optional monetaryValue, status: open|won|lost|abandoned)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"PUT","path":"/pipeline/opportunities/:id","scope":"pipeline.write","summary":"Update an opportunity","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"DELETE","path":"/pipeline/opportunities/:id","scope":"pipeline.write","summary":"Delete an opportunity (permanent, removed from GHL too)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/transactions","scope":"transactions.read","summary":"List transactions (optional type=buy|sell, contactId)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"POST","path":"/transactions","scope":"transactions.write","summary":"Create a transaction (type/propertyAddress required; contactId optional — omitting it provisions a contact from the deal name; optional price, dealStatus: active|under_contract, closeDate, sellerDisclosureDeadline, dueDiligenceDeadline, financingAppraisalDeadline — all four deadlines required when under_contract; dates are ISO datetimes)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/transactions/:id","scope":"transactions.read","summary":"Get a transaction (id = opportunity id)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"PUT","path":"/transactions/:id","scope":"transactions.write","summary":"Update a transaction (any create field plus pipelineStageId/status; setting dealStatus back to active clears all deadlines)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"DELETE","path":"/transactions/:id","scope":"transactions.write","summary":"Delete a transaction (removes the GHL opportunity and the deal metadata)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/marketing/accounts","scope":"marketing.read","summary":"List connected social accounts","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/marketing/posts","scope":"marketing.read","summary":"List social posts (optional fromDate/toDate/accountIds/status)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"POST","path":"/marketing/posts","scope":"marketing.write","summary":"Create or schedule a social post","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/inbox/conversations","scope":"inbox.read","summary":"List conversations (optional search/contactId)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"POST","path":"/inbox/conversations","scope":"inbox.write","summary":"Start a conversation with a contact","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/inbox/conversations/:id/messages","scope":"inbox.read","summary":"Read a conversation thread","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"POST","path":"/inbox/conversations/:id/messages","scope":"inbox.write","summary":"Send a message in a conversation","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/webhooks","scope":"webhooks.read","summary":"List registered webhook endpoints (signing secrets are never returned again)","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"POST","path":"/webhooks","scope":"webhooks.write","summary":"Register a webhook endpoint. Events: message.inbound (reply lands in the inbox), contact.created (new GHL contact), opportunity.stage_changed (pipeline stage move), transaction.closed (closeDate first persisted). Deliveries are JSON POSTs with X-Relay-Event, X-Relay-Timestamp, and X-Relay-Signature: v1=HMAC_SHA256(secret, timestamp + \".\" + rawBody) — verify with the secret returned once here. Best-effort delivery (one retry); keep polling as a fallback for missed events.","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"DELETE","path":"/webhooks/:id","scope":"webhooks.write","summary":"Remove a webhook endpoint","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."},{"method":"GET","path":"/users","scope":"users.read","summary":"List your account's team members, including deactivated ones (isActive: false) since historical records still reference them. ghlUserId is the id that contact/opportunity assignedTo fields reference — use it to attribute CRM records to people in an external system. name and ghlUserId are null for members never linked to the CRM.","reason":"Schema registration follows the planned service migration. Existing behavior remains supported; examples are illustrative subsets."}]}