endedReason says why a call ended. It is a string passed through from the telephony and voice layers, so new values can appear: map the ones you know and send the others to a default bucket rather than rejecting them.
Not reached
customer-did-not-answer
Nobody picked up
customer-busy
The line was busy
customer-declined
The call was declined
voicemail
A voicemail answered
customer-unavailable
The number could not be reached
customer-number-not-found
The number does not exist
no-international-permission
The line may not call that country
outbound-call-forbidden
The line may not place outbound calls
Ended during the conversation
customer-ended-call
The caller hung up
assistant-ended-call
The agent hung up, through an endCall node
silence-timed-out
The caller was silent longer than silenceTimeoutSeconds
max-duration-exceeded, exceeded-max-duration
The call reached maxDurationSeconds
Transfers
assistant-forwarded-call
The agent transferred the call
customer-ended-call-during-transfer
The caller hung up during the transfer
error-transfer-failed
The transfer failed
error-transfer-destination-busy
The transfer number was busy
error-transfer-destination-unreachable
The transfer number could not be reached
Not dialed
contact-opted-out
The contact opted out
agent-line-entity-mismatch
The campaign's agent and number belong to different entities; the campaign stops
cps-limit-exceeded
The trunk's calls-per-second limit was reached
twilio-call-permission
The Twilio account refused the call
dial-failed
The call could not be placed
Technical
sip-server-error, sip-trunk-failure
The carrier or the trunk returned an error
stuck-in-progress
A call that never reported its end, closed by CallShift