The Latter Years API
Connect your own CRM or website to Latter Years. Post leads and residents, edit them and set their status, read your conversations with families, log a message your system already sent or send one through us, and make a family’s referral link. Every call acts as your organization, through a key you create and can revoke.
The same reference as an OpenAPI 3.1 document, for code generators and API clients: /api/v1/openapi.json
curl -X POST https://latteryears.com/api/v1/intake/leads \
-H "Authorization: Bearer ly_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: webform-48213" \
-d '{
"contact": { "first_name": "Dana", "phone": "(801) 555-0142" },
"loved_one": { "first_name": "Margaret" },
"origin_kind": "website"
}'Keys
- An administrator creates a key on the API keys page in Latter Years. A key looks like ly_ followed by 48 characters: a 16-character prefix you will see on the page afterwards, and a 32-character secret shown once, when it is created. We keep only a hash of it.
- Send it on every request as Authorization: Bearer ly_… over HTTPS.
- Your organization can have 5 live keys at a time, so you can create the new one, move your system to it, then revoke the old one with no gap.
- A key can be bound to one of your locations. Then what it posts lands there, and it reads and edits that location’s leads and residents only. A record anywhere else answers 404, as if it did not exist.
- A key that posts residents carries your attestation: how and when your organization got the families’ consent to be contacted. The contacts it posts are recorded under that attestation, and a key without it cannot post residents.
- A key acts as the person who created it, so its changes show on your timeline as made via the key’s name. If that person leaves your team, revoke the key and create a new one: until you do, it can still post leads and residents, and everything else answers 403 key_not_usable.
Scopes
Each key holds a set of scopes, chosen when it is created. An endpoint the key has no scope for answers 403 with the scope it needs in required_scope.
leads:write- Add families who reached out to you. POST /api/v1/intake/leads, POST /api/v1/intake/leads/batch, GET /api/v1/leads, PATCH /api/v1/leads/{id}
residents:write- Send your roster. Needs the consent attestation below. POST /api/v1/intake/residents, POST /api/v1/intake/residents/batch, PATCH /api/v1/residents/{id}
messages:read- Read the messages in your conversations with families. GET /api/v1/conversations, GET /api/v1/conversations/{id}/messages
messages:write- Add a message your own system already sent to the conversation. POST /api/v1/conversations/{id}/messages
messages:send- Send a message to a family, with every rule a typed message follows. POST /api/v1/conversations/{id}/messages
referral_links:write- Create a family link from one of your packets. POST /api/v1/referral-links
metrics:read- Read the numbers on your Reports page. No endpoint uses this scope yet.
Limits
Each limit is per key, counted over the window shown. Over it, the endpoint answers 429 rate_limited; wait and retry. A batch holds at most 500 rows.
POST /api/v1/intake/residents- 60 per 60 seconds
POST /api/v1/intake/residents/batch- 6 per 60 seconds
POST /api/v1/intake/leads- 60 per 60 seconds
POST /api/v1/intake/leads/batch- 6 per 60 seconds
GET /api/v1/leads- 60 per 60 seconds
PATCH /api/v1/leads/{id}- 120 per 60 seconds
PATCH /api/v1/residents/{id}- 120 per 60 seconds
GET /api/v1/conversations- 60 per 60 seconds
GET /api/v1/conversations/{id}/messages- 300 per 60 seconds
POST /api/v1/conversations/{id}/messages(delivery "external")- 120 per 60 seconds
POST /api/v1/conversations/{id}/messages(delivery "send")- 30 per 60 seconds
POST /api/v1/referral-links- 60 per 60 seconds
Retries and Idempotency-Key
- Send an Idempotency-Key header (1 to 255 characters, one you make up for each new request) on every write. Logging or sending a message and making a referral link require it, and answer 400 idempotency_key_required without it. Posting and editing leads and residents take it too, and you should send it.
- A retry with the same key and the same body never does the thing twice. It answers the first result again, with replayed: true.
- The same key with a different body answers 409 idempotency_key_reuse. Use a new key for a new request, and never reuse an old one.
- We remember a key’s answer for 90 days (30 days for a lead or resident post). A referral link’s key past that answers 409 idempotency_key_spent.
- Sending a message: a 500 send_unconfirmed means something failed once sending had begun, so we cannot say whether the family received it. Read the conversation before you send it again, under a new key. A 500 send_failed means nothing reached the family; send it again under a new key. Either answer stays with its key.
- A held message was not sent and is not queued. Send it again after retry_at, under a new key.
Errors
Every refusal is JSON with a stable error code to branch on and a message for a person. Field problems come as a list instead.
{ "error": "not_found", "message": "No lead with that id." }
{ "error": "validation_failed", "errors": [ { "field": "contact.email", "message": "contact.email must be a valid email address." } ] }- 400
- validation_failed with errors: [{ field, message }], invalid_json, or a missing or unusable Idempotency-Key. (Posting leads and residents answers field problems with 422 instead.)
- 401
- unauthorized. One answer for a missing, malformed, unknown or revoked key.
- 403
- forbidden with required_scope, or key_not_usable when the key’s creator has left your team.
- 404
- not_found. One answer for an id that does not exist and one that is outside your organization, or outside the key’s location.
- 409
- The request conflicts with what is there: idempotency_key_reuse, idempotency_key_spent, in_progress, messaging_not_active, or a record not in a state for that change.
- 413
- batch_too_large.
- 422
- Well formed, but this record cannot take it; field names what to fix where one applies.
- 429
- rate_limited.
- 500
- server_error: ours, and nothing was saved. Sending a message also has send_unconfirmed and send_failed (above).
- 503
- not_configured: that endpoint cannot run just now. Try again later.
Endpoints
Every endpoint, with what it takes and what it answers. Fields marked required must be sent; every other field may be left out. An unknown field is refused, not ignored.
post/api/v1/intake/residents
Post one resident
Adds one resident, or updates the one you already sent (matched on external_system and external_id, then phone, then name and date of birth), and answers with its id. The same duplicate detection and consent handling as a CSV import. Contacts are recorded under the attestation on the key. Nothing is sent to the family.
- Scope
residents:write- Limit
- 60 per 60 seconds (shared with posting one lead)
- Idempotency-Key
- Recommended
Body
external_system- string. up to 100 characters
external_id- string. up to 200 characters
first_namerequired- string. up to 100 characters
last_namerequired- string. up to 100 characters
phone- string
date_of_birth- string
move_in_date- string
status- string. one of: active, discharged, moved_out, deceased
assigned_user_email- string (email). up to 254 characters
location- string. up to 200 characters
origin_kind- string. one of: marketplace, referral_site, placement_agent, professional_referral, website, phone_walk_in, word_of_mouth, event_outreach, other, unknown
origin_name- string. up to 200 characters
contacts- object[]. at most 10
contacts[].namerequired- string. up to 200 characters
contacts[].phone- string
contacts[].email- string (email). up to 254 characters
contacts[].relationshiprequired- string. one of: POA, spouse, child, sibling, friend, other
contacts[].preferred_contact_method- string. one of: call, text, email
contacts[].is_primary- boolean
consent_captured_on- string
consent_source- string. up to 500 characters
Answer (201)
batch_idrequired- string (uuid)
resident_idrequired- string (uuid) or null
statusrequired- string. created or updated (a match on external_id, phone, or name and date of birth). A replay answers the first request’s status as it stands: check it is one of those two before treating the replay as saved.
replayedrequired- boolean
Responses
- 200
- Updated an existing resident, or a replay of the first answer under the same Idempotency-Key.
- 201
- Created.
- 400
- The body is not valid JSON.
invalid_json - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but lacks the scope this endpoint needs (required_scope names it).
forbidden - 409
- The Idempotency-Key was already used for a different payload.
idempotency_key_reuse - 422
- A field is refused (errors names each one), or the resident could not be imported (row_rejected), or was not imported because no contact can be reached (row_skipped).
validation_failed,row_rejected,row_skipped - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
post/api/v1/intake/residents/batch
Post many residents
Accepts up to the batch limit of residents at once and imports them in the background. If any row is invalid the whole batch is refused with every field-named error, and nothing is imported. Repeat the request with the same Idempotency-Key to see how far the batch has got.
- Scope
residents:write- Limit
- 6 per 60 seconds (shared with posting many leads)
- Idempotency-Key
- Recommended
Body
residentsrequired- object[]. At most 500; more answers 413 batch_too_large.
residents[].external_system- string. up to 100 characters
residents[].external_id- string. up to 200 characters
residents[].first_namerequired- string. up to 100 characters
residents[].last_namerequired- string. up to 100 characters
residents[].phone- string
residents[].date_of_birth- string
residents[].move_in_date- string
residents[].status- string. one of: active, discharged, moved_out, deceased
residents[].assigned_user_email- string (email). up to 254 characters
residents[].location- string. up to 200 characters
residents[].origin_kind- string. one of: marketplace, referral_site, placement_agent, professional_referral, website, phone_walk_in, word_of_mouth, event_outreach, other, unknown
residents[].origin_name- string. up to 200 characters
residents[].contacts- object[]. at most 10
residents[].contacts[].namerequired- string. up to 200 characters
residents[].contacts[].phone- string
residents[].contacts[].email- string (email). up to 254 characters
residents[].contacts[].relationshiprequired- string. one of: POA, spouse, child, sibling, friend, other
residents[].contacts[].preferred_contact_method- string. one of: call, text, email
residents[].contacts[].is_primary- boolean
residents[].consent_captured_on- string
residents[].consent_source- string. up to 500 characters
Answer (202)
batch_idrequired- string (uuid)
statusrequired- string. always "processing"
acceptedrequired- integer. -9007199254740991 to 9007199254740991
replayedrequired- boolean. always "false"
Responses
- 200
- A replay under the same Idempotency-Key: the batch and its counts so far.
- 202
- Accepted; the import runs in the background.
- 400
- The body is not valid JSON.
invalid_json - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but lacks the scope this endpoint needs (required_scope names it).
forbidden - 409
- The Idempotency-Key was already used for a different payload.
idempotency_key_reuse - 413
- More rows than one batch can hold.
batch_too_large - 422
- At least one row is refused; errors names each row and field. Nothing was imported.
validation_failed - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
post/api/v1/intake/leads
Post one lead
Adds a family who reached out to you, from your website form or another system. A family you already have is an answer, not an error: 200 with status duplicate and the record you have. Posting a lead sends nothing: the family has not agreed to texts or emails from Latter Years yet.
- Scope
leads:write- Limit
- 60 per 60 seconds (shared with posting one resident)
- Idempotency-Key
- Recommended
Body
contactrequired- object
contact.first_namerequired- string. up to 100 characters
contact.last_name- string. up to 100 characters
contact.phone- string. up to 40 characters
contact.email- string (email). up to 254 characters
loved_onerequired- object
loved_one.first_namerequired- string. up to 100 characters
loved_one.last_name- string. up to 100 characters
loved_one.date_of_birth- string
location- string. up to 200 characters
origin_kindrequired- string. one of: referral_site, placement_agent, professional_referral, website, phone_walk_in, word_of_mouth, event_outreach, other
origin_name- string. up to 200 characters
inquiry_at- string (date-time)
consent_captured_on- string
consent_source- string. up to 500 characters
Answer (201)
batch_idrequired- string (uuid)
lead_idrequired- string (uuid) or null
statusrequired- string. always "created"
replayedrequired- boolean
Responses
- 200
- A family you already have (status duplicate), or a replay of the first answer.
- 201
- Created.
- 202
- Still being saved by an earlier request under the same Idempotency-Key. Ask again in a moment.
- 400
- The body is not valid JSON.
invalid_json - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but lacks the scope this endpoint needs (required_scope names it).
forbidden - 409
- The Idempotency-Key was already used for a different payload.
idempotency_key_reuse - 422
- A field is refused (errors names each one), or the lead could not be imported (row_rejected).
validation_failed,row_rejected - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
post/api/v1/intake/leads/batch
Post many leads
Accepts up to the batch limit of leads at once and imports them in the background, all or nothing on validation. A family repeated within one batch is added once.
- Scope
leads:write- Limit
- 6 per 60 seconds (shared with posting many residents)
- Idempotency-Key
- Recommended
Body
leadsrequired- object[]. At most 500; more answers 413 batch_too_large.
leads[].contactrequired- object
leads[].contact.first_namerequired- string. up to 100 characters
leads[].contact.last_name- string. up to 100 characters
leads[].contact.phone- string. up to 40 characters
leads[].contact.email- string (email). up to 254 characters
leads[].loved_onerequired- object
leads[].loved_one.first_namerequired- string. up to 100 characters
leads[].loved_one.last_name- string. up to 100 characters
leads[].loved_one.date_of_birth- string
leads[].location- string. up to 200 characters
leads[].origin_kindrequired- string. one of: referral_site, placement_agent, professional_referral, website, phone_walk_in, word_of_mouth, event_outreach, other
leads[].origin_name- string. up to 200 characters
leads[].inquiry_at- string (date-time)
leads[].consent_captured_on- string
leads[].consent_source- string. up to 500 characters
Answer (202)
batch_idrequired- string (uuid)
statusrequired- string. always "processing"
acceptedrequired- integer. -9007199254740991 to 9007199254740991
replayedrequired- boolean. always "false"
Responses
- 200
- A replay under the same Idempotency-Key: the batch and its counts so far.
- 202
- Accepted; the import runs in the background.
- 400
- The body is not valid JSON.
invalid_json - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but lacks the scope this endpoint needs (required_scope names it).
forbidden - 409
- The Idempotency-Key was already used for a different payload.
idempotency_key_reuse - 413
- More rows than one batch can hold.
batch_too_large - 422
- At least one row is refused; errors names each row and field. Nothing was imported.
validation_failed - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
get/api/v1/leads
List leads
Your leads (at the key’s location, when it has one), oldest change first, for a sync. Pass next_cursor back as cursor for the next page. A change appears about ten seconds after it is made, and a tag change alone does not move updated_at. contact is null while the family has not shared it with you.
- Scope
leads:write- Limit
- 60 per 60 seconds
Query
since- string (date-time)
cursor- string. up to 200 characters
limit- integer. 1 to 100
Answer (200)
leadsrequired- object[]
leads[].idrequired- string (uuid)
leads[].location_idrequired- string (uuid) or null
leads[].listing_idrequired- string (uuid) or null
leads[].statusrequired- string
leads[].outcomerequired- string or null
leads[].close_reasonrequired- string or null
leads[].patient_statusrequired- string or null
leads[].automations_pausedrequired- boolean or null
leads[].origin_kindrequired- string or null
leads[].origin_namerequired- string or null
leads[].intake_channelrequired- string or null
leads[].inquiry_atrequired- string or null. An ISO 8601 time.
leads[].created_atrequired- string. An ISO 8601 time.
leads[].updated_atrequired- string. An ISO 8601 time.
leads[].created_by_api_key_idrequired- string (uuid) or null
leads[].tagsrequired- string[]
leads[].loved_onerequired- object
leads[].loved_one.first_namerequired- string or null
leads[].loved_one.last_namerequired- string or null
leads[].contactrequired- object or null
leads[].contact.first_namerequired- string or null
leads[].contact.last_namerequired- string or null
leads[].contact.phonerequired- string or null
leads[].contact.emailrequired- string or null
next_cursorrequired- string or null
Responses
- 200
- One page of leads.
- 400
- A query value is refused, or the cursor is not one this API returned.
validation_failed - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but may not do this: it lacks the scope (forbidden, naming required_scope), or the person who created it is no longer on your team (key_not_usable).
forbidden,key_not_usable - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
patch/api/v1/leads/{id}
Edit a lead or set its status
Changes only what you send. contact can change while the family has not taken over their own details; tags add and remove (a new name joins your tag list); status is contacted, open, or closed with a close_reason; an agency can set patient_status. Nothing is ever deleted: a lead is closed. Anything the family wrote cannot be sent and is refused. A status that stops messages pauses the family’s sequences, as it does on the lead page. Every change shows on the lead’s timeline as made via your key.
- Scope
leads:write- Limit
- 120 per 60 seconds
- Idempotency-Key
- Recommended
Body
contact- object
contact.first_name- string. up to 100 characters
contact.last_name- string or null. up to 100 characters
contact.phone- string or null
contact.email- string (email) or null. up to 254 characters
inquiry_at- string (date-time)
tags- object
tags.add- string[]. at most 20
tags.remove- string[]. at most 20
status- string. one of: contacted, open, closed
close_reason- string. one of: no_availability, not_a_fit, lost_to_other, unresponsive, passed_away, hospitalized, stayed_home, another_agency, could_not_staff, outside_area, payment, care_not_provided, no_response, declined, referral_elsewhere, moved_nursing_home, hospice_instead, home_health_instead
close_reason_text- string. up to 200 characters
close_note- string. up to 5000 characters
close_payer- string
close_same_organization- boolean
close_checkin_days- integer. 1 to 30
patient_status- string or null. one of: passed_away, back_in_hospital, moved_to_hospice, left_hospice_alive, moved_assisted_living, moved_nursing_home, care_finished, switched_agency, asked_to_stop, back_on_service
patient_status_same_organization- boolean
Answer (200)
lead_idrequired- string (uuid)
changedrequired- string[]. The fields this change wrote.
replayedrequired- boolean
Responses
- 200
- Saved (or a replay of the first answer under the same Idempotency-Key).
- 400
- The body or query is not one this endpoint takes: invalid JSON, or a field it refuses, named in errors.
validation_failed,invalid_json - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but may not do this: it lacks the scope (forbidden, naming required_scope), or the person who created it is no longer on your team (key_not_usable).
forbidden,key_not_usable - 404
- No lead with that id for this key.
not_found - 409
- The lead is not in a state for that change, or the Idempotency-Key was used for a different change.
family_owns_contact,contact_opted_out,status_conflict,family_closed,care_not_started,retry,idempotency_key_reuse - 422
- A well-formed change this lead cannot take; field names it.
not_applicable,invalid_value,invalid_tag,invalid_close_reason,too_many_tags,tag_list_full,same_organization_required - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
patch/api/v1/residents/{id}
Edit a resident or set their status
Changes only what you send: names, phone, dates, status with its move_out_date and move_out_reason (they travel together), tags, and for an agency patient_status. Nothing is ever deleted: a resident moves out.
- Scope
residents:write- Limit
- 120 per 60 seconds
- Idempotency-Key
- Recommended
Body
first_name- string. up to 100 characters
last_name- string. up to 100 characters
phone- string or null
date_of_birth- string or null
move_in_date- string or null
status- string. one of: active, discharged, moved_out, deceased
move_out_date- string or null
move_out_reason- string or null. one of: higher_level_of_care, hospital, deceased, cost, family_decision, dissatisfied, other
tags- object
tags.add- string[]. at most 20
tags.remove- string[]. at most 20
patient_status- string or null. one of: passed_away, back_in_hospital, moved_to_hospice, left_hospice_alive, moved_assisted_living, moved_nursing_home, care_finished, switched_agency, asked_to_stop, back_on_service
patient_status_kind- string. one of: home_health, hospice, personal_care
patient_status_same_organization- boolean
Answer (200)
resident_idrequired- string (uuid)
changedrequired- string[]. The fields this change wrote.
replayedrequired- boolean
Responses
- 200
- Saved (or a replay of the first answer under the same Idempotency-Key).
- 400
- The body or query is not one this endpoint takes: invalid JSON, or a field it refuses, named in errors.
validation_failed,invalid_json - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but may not do this: it lacks the scope (forbidden, naming required_scope), or the person who created it is no longer on your team (key_not_usable).
forbidden,key_not_usable - 404
- No resident with that id for this key.
not_found - 409
- The resident is not in a state for that change, or the Idempotency-Key was used for a different change.
care_not_started,retry,idempotency_key_reuse - 422
- A well-formed change this resident cannot take; field names it.
not_applicable,invalid_value,invalid_tag,too_many_tags,tag_list_full,same_organization_required - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
get/api/v1/conversations
List conversations
The leads whose thread changed, oldest change first. id is the lead’s id; last_activity_at moves when a message arrives or the lead’s status changes. Takes since, cursor and limit as leads do (a cursor works only where it came from).
- Scope
messages:read- Limit
- 60 per 60 seconds
Query
since- string (date-time)
cursor- string. up to 200 characters
limit- integer. 1 to 100
Answer (200)
conversationsrequired- object[]
conversations[].idrequired- string (uuid)
conversations[].location_idrequired- string (uuid) or null
conversations[].listing_idrequired- string (uuid) or null
conversations[].last_activity_atrequired- string
conversations[].last_message_atrequired- string or null
next_cursorrequired- string or null
Responses
- 200
- One page of conversations.
- 400
- A query value is refused, or the cursor is not one this API returned.
validation_failed - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but may not do this: it lacks the scope (forbidden, naming required_scope), or the person who created it is no longer on your team (key_not_usable).
forbidden,key_not_usable - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
get/api/v1/conversations/{id}/messages
Read one conversation
One lead’s thread as the family saw it, oldest change first. A message sent securely is listed with held_in_app true and no body; the text or email that told the family about it is its own message with secure_notice true. Notes, the assistant’s reasoning, drafts never sent and other organizations’ messages are never included. Each thread you read is recorded in your access log under the key’s creator.
- Scope
messages:read- Limit
- 300 per 60 seconds
Query
since- string (date-time)
cursor- string. up to 200 characters
limit- integer. 1 to 100
Answer (200)
messagesrequired- object[]
messages[].idrequired- string (uuid)
messages[].conversation_idrequired- string (uuid)
messages[].directionrequired- string. one of: inbound, outbound
messages[].channelrequired- string. one of: sms, email, portal
messages[].bodyrequired- string or null
messages[].held_in_apprequired- boolean
messages[].secure_noticerequired- boolean
messages[].statusrequired- string
messages[].subjectrequired- string or null
messages[].sent_atrequired- string or null
messages[].received_atrequired- string or null
messages[].updated_atrequired- string
messages[].authorrequired- object
messages[].author.kindrequired- string. one of: family, staff, assistant, automation, api_key
messages[].author.api_key_idrequired- string (uuid) or null
messages[].author.api_key_labelrequired- string or null
next_cursorrequired- string or null
Responses
- 200
- One page of messages.
- 400
- A query value is refused, or the cursor is not one this API returned.
validation_failed - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but may not do this: it lacks the scope (forbidden, naming required_scope), or the person who created it is no longer on your team (key_not_usable).
forbidden,key_not_usable - 404
- No conversation with that id for this key.
not_found - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error
post/api/v1/conversations/{id}/messages
Log a message you sent, or send one
delivery "external" adds a text or email your own system already sent: we store it and never send it, and it counts as your team answering. delivery "send" sends it exactly as a reply typed in Latter Years is sent: every opt-out, consent rule, quiet hours and your daily allowance apply. Left out, channel is a text when the family has shared a phone, otherwise their Latter Years page, and a refusal is never retried on another channel. sensitive true (or anything we find about health or money) keeps the words on their Latter Years page and the family gets a notice with a secure link. outcome says what happened: sent, sent_as_secure_notice, held (send it again after retry_at under a new Idempotency-Key; nothing is queued), or refused.
- Scope
messages:writefor delivery "external";messages:sendfor delivery "send"- Limit
- 120 per 60 seconds for delivery "external"; 30 per 60 seconds for delivery "send"
- Idempotency-Key
- Required
Body
delivery: "external"
deliveryrequired- string. always "external"
channelrequired- string. one of: sms, email
bodyrequired- string. up to 5000 characters
subject- string. up to 200 characters
sensitive- boolean
delivery: "send"
deliveryrequired- string. always "send"
channel- string. one of: sms, email, portal
bodyrequired- string. up to 5000 characters
subject- string. up to 200 characters
sensitive- boolean
Answer (201)
delivery: "external"
message_idrequired- string (uuid)
conversation_idrequired- string (uuid)
deliveryrequired- string. always "external"
channelrequired- string. one of: sms, email
held_in_apprequired- boolean
logged_atrequired- string
replayedrequired- boolean
delivery: "send"
conversation_idrequired- string (uuid)
deliveryrequired- string. always "send"
outcomerequired- string. one of: sent, sent_as_secure_notice, held, refused
channelrequired- string. one of: sms, email, portal
message_idrequired- string (uuid) or null
notice_channelrequired- string or null. one of: in_app, sms, email
deliveredrequired- boolean or null
mockedrequired- boolean or null
reasonrequired- string or null
reason_messagerequired- string or null
retry_atrequired- string or null
answered_atrequired- string
replayedrequired- boolean
Responses
- 200
- A replay under the same Idempotency-Key and body: the first answer again, and never a second send.
- 201
- Logged (delivery external) or answered (delivery send: read outcome).
- 400
- No usable Idempotency-Key header, invalid JSON, a field refused (errors names it), or an email with no subject.
validation_failed,invalid_json,idempotency_key_required,idempotency_key_invalid - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but may not do this: it lacks the scope (forbidden, naming required_scope), or the person who created it is no longer on your team (key_not_usable).
forbidden,key_not_usable - 404
- No conversation with that id for this key.
not_found - 409
- The Idempotency-Key was used for a different message; the first send under it is still going (in_progress: ask again in a moment); or messaging is not active for this lead yet, where your team could not reply either.
idempotency_key_reuse,in_progress,messaging_not_active - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- send_unconfirmed: something failed once sending had begun, so we cannot confirm whether the family received it. Read the conversation before sending again, under a new key. send_failed: nothing reached the family; send it again under a new key. Both answers stay with that Idempotency-Key. server_error: nothing was sent; the same key may be retried.
send_unconfirmed,send_failed,server_error
post/api/v1/referral-links
Make a referral link
A family’s link from one of your organization’s packets, sent from one of your buildings (its county is the area the family’s list covers; without one the list is statewide; a key bound to a building uses its own). Send nothing about the family: the link carries the packet and the area only. Each Idempotency-Key makes exactly one link, and repeating the request returns the same link. The link expires after 30 days.
- Scope
referral_links:write- Limit
- 60 per 60 seconds
- Idempotency-Key
- Required
Body
packet_idrequired- string (uuid)
location_id- string (uuid) or null
care_kind- string. one of: home_health, hospice, nursing_care, assisted_living, memory_care, personal_care
Answer (201)
link_idrequired- string (uuid)
packet_idrequired- string (uuid)
location_idrequired- string (uuid) or null
countyrequired- string or null
care_kindrequired- string or null. one of: home_health, hospice, nursing_care, assisted_living, memory_care, personal_care
created_atrequired- string
expires_atrequired- string
urlrequired- string (uri)
replayedrequired- boolean
Responses
- 200
- A replay: the same link again.
- 201
- Made.
- 400
- No usable Idempotency-Key header, invalid JSON, or a field refused (errors names it).
validation_failed,invalid_json,idempotency_key_required,idempotency_key_invalid - 401
- No key, or not a live key. Every failure here is the same answer.
unauthorized - 403
- The key is real but may not do this: it lacks the scope (forbidden, naming required_scope), or the person who created it is no longer on your team (key_not_usable).
forbidden,key_not_usable - 404
- No packet or location with that id for this key.
not_found - 409
- The Idempotency-Key was used for a different request (idempotency_key_reuse), or its link can no longer be handed back (idempotency_key_spent): use a new key.
idempotency_key_reuse,idempotency_key_spent - 422
- The packet needs a care_kind and none was sent (or a different one was), or the building is in another state than your organization.
care_kind_invalid,location_out_of_state - 429
- Over this key’s rate limit for this endpoint. Retry shortly.
rate_limited - 500
- Our failure. Nothing was saved; retry.
server_error - 503
- Links cannot be made just now. Try again later.
not_configured
get/api/v1/openapi.json
This document
The OpenAPI 3.1 description of every /api/v1 endpoint. No key needed.
- Scope
- None: no key needed.
Responses
- 200
- The OpenAPI document.