본문으로 건너뛰기

메시지

수신 거부 링크와 일일 한도가 적용되는, 지원자에게 보내는 이메일.

엔드포인트 하나로, 내 공고에 지원한 사람 한 명에게 이메일을 보냅니다. 연동 프로그램이 내 도구 안에서 후보자에게 연락할 수 있게 하되, Tahoe 제품과 같은 안전장치를 적용하기 위한 것입니다. 수신 거부 링크, 수신 거부 목록, 일일 한도가 그것입니다.

POST/messagesmessages:send

이메일 한 통을 보내고, 메일 제공자가 받아들이면 200을 반환합니다. Tahoe 사용자가 만든 API 키가 필요합니다. Sign in with Tahoe 토큰은 403 write_requires_api_key를 받습니다. 연결된 앱의 쓰기가 켜져 있으면 예외입니다. messages:send는 유료 플랜 스코프입니다.

필드타입설명
toobject, 필수application_id(app_ 핸들)와 applicant_id(apl_ 핸들) 중 정확히 하나. 둘 다 있거나 둘 다 없으면 400 invalid_request입니다. 이메일 주소를 넣는 필드는 없으며 받지도 않습니다. 주소는 내 워크스페이스에 있는 그 사람의 Tahoe 기록에서 읽습니다.
subjectstring, 필수1~200자. 한 줄이어야 하며 공백만 있으면 안 됩니다.
body_textstring, 필수1~20,000자이며 공백만 있으면 안 됩니다. 이메일의 텍스트 부분이고, HTML을 표시하지 않는 메일 앱을 위한 대체 내용입니다.
body_htmlstring선택. 최대 50,000자. Tahoe가 보내기 전에 기본 서식을 제외한 모든 것을 제거합니다.
reply_to_userboolean선택. 받아 주지만 무시합니다. 답장은 항상 키가 대신하는 Tahoe 사용자에게 갑니다.
요청
curl -X POST https://tahoe.workonward.com/api/partner/v1/messages \
  -H "Authorization: Bearer $TAHOE_API_KEY" \
  -H "Idempotency-Key: msg-6Qm2-next-steps-0001" \
  -H "Content-Type: application/json" \
  -d '{
    "to": { "application_id": "app_6Qm2xKd4Rp8v" },
    "subject": "Next steps for the Backend Engineer role",
    "body_text": "Hi Jane,\n\nThanks for applying. Are you free for a call on Thursday?\n\nRecruiting team",
    "body_html": "<p>Hi Jane,</p><p>Thanks for applying. Are you free for a call on Thursday?</p>"
  }'
응답: 200
{
  "id": "msg_Zm9vQm1hcjR3",
  "status": "sent",
  "to": { "application_id": "app_6Qm2xKd4Rp8v" },
  "sent_at": "2026-10-08T14:03:11.482913Z"
}
  • id는 메시지의 msg_ 핸들입니다. 저장해 두고 해석하지 마세요.
  • status는 메일 제공자가 메시지를 받아들였을 때 sent이고, 같은 키의 이전 요청이 아직 전달 중이면 queued입니다. sent는 상대가 읽었다거나 받은편지함에 도착했다는 뜻이 아닙니다.
  • to는 보낸 핸들의 종류를 표준 형태로 되풀이합니다. 응답에는 이메일 주소, 이름, 메시지 내용이 없습니다.
  • sent_at은 제공자가 받아들인 시각(UTC)이며, status가 queued인 동안은 null입니다.
  • 이 호출은 expensive 속도 제한 등급에 속합니다. 리크루터가 메시지를 보낼 때 제품이 이벤트를 보내지 않으므로 이 호출도 이벤트를 보내지 않습니다.

받는 사람이 보는 것

  • 이메일은 Tahoe 제품이 보내는 모든 이메일과 마찬가지로 내 도메인이 아니라 Tahoe의 공용 발신 주소에서 갑니다. Reply-To는 키를 만든 Tahoe 사용자의 이메일이므로 답장은 그 사람의 메일함에 도착하며, 요청마다 바꿀 수 없습니다. Tahoe에는 받은편지함이 없고 답장을 읽지 않습니다.
  • 모든 메시지 끝에 Tahoe의 수신 거부 안내가 붙고 원클릭 List-Unsubscribe 헤더가 포함됩니다. 끄거나 수정할 수 없습니다. 안내의 링크를 누르면 그 워크스페이스에 대해 Tahoe를 통해 보내는 이메일의 수신이 거부됩니다.
  • 응답을 돌려주기 전에 메일 제공자에게 전달을 넘깁니다. example.com 같은 예약된 테스트 주소로는 메일을 보내지 않으며 409 recipient_unsubscribed를 반환합니다.

팀이 보는 것

메시지는 제목, 텍스트, 정리된 HTML, 수신자, 발신자, 상태와 함께 저장되며, 키를 만든 사용자가 보낸 것처럼 Tahoe의 그 사람 보낸 이메일 목록에 나타납니다. 지원서 타임라인에, 또는 수신자를 지원자로 지정했다면 워크스페이스 활동에 email_sent 항목이 생깁니다. 수신자 주소, 제목, 전달 상태가 기록되고 키를 만든 사람이 한 것으로 표시됩니다.

이메일을 보낼 수 있는 사람

키의 워크스페이스에 지원한 사람, 즉 지원자와 그 지원서만 해당합니다. 지원하지 않은 소싱한 프로필에는 이 엔드포인트로 이메일을 보낼 수 없습니다. 세 가지 기록을 확인하며, 하나라도 해당하면 발송이 중단됩니다.

  • 그 워크스페이스에서 본인이 한 수신 거부
  • 워크스페이스의 아웃리치 수신 거부 목록
  • Tahoe의 처리 중단 및 삭제 기록. 사람의 데이터를 지운 뒤에도 유지되며 워크스페이스를 넘어 적용됩니다.

이 중 하나라도 읽을 수 없으면 아무것도 보내지 않습니다. 거부된 발송은 409 recipient_unsubscribed를 반환하며 다시 시도하지 마세요.

409 Conflict
{
  "detail": {
    "code": "recipient_unsubscribed",
    "type": "conflict",
    "message": "This person cannot be emailed. Nothing was sent.",
    "param": null
  }
}

body_html 필드

Tahoe 제품의 발송 경로는 로그인한 리크루터만 쓸 수 있으므로 HTML을 정리하지 않습니다. 이 엔드포인트는 호출하는 쪽이 프로그램이므로 HTML을 정리합니다.

  • 유지되는 것: a(http, https, mailto 링크만 가능하며 rel="noopener noreferrer nofollow"로 바뀝니다), b, strong, i, em, u, p, br, hr, div, span, ul, ol, li, blockquote, h1~h4, code, pre. 링크 주소를 제외한 모든 속성이 제거됩니다.
  • 내용째 제거되는 것: script, style, iframe, object, embed, svg, math, form과 입력 요소. 그 밖의 태그는 태그만 제거되고 텍스트는 남습니다.
  • 이미지는 허용되지 않습니다. 정리한 뒤 남는 것이 없으면 HTML 보기에도 텍스트 부분만 씁니다.

한도

키 하나는 기본적으로 UTC 하루에 최대 200통을 보낼 수 있습니다. 분당 요청 제한과는 별개입니다. 넘으면 429 message_quota_exceeded를 반환하고, Retry-After는 UTC 자정까지 남은 초입니다. 실패한 요청은 한도를 소모하지 않습니다.

재시도

  • 키는 자격 증명, 워크스페이스, 경로에 묶이며 기록은 24시간 유지됩니다. 같은 키와 같은 본문이면 첫 응답이 Idempotent-Replayed: true와 함께 돌아오고 두 번째 이메일은 보내지 않습니다. 같은 키에 다른 본문이면 409 idempotency_key_reused입니다.
  • 키는 Tahoe의 발송 이메일 기록에도 저장됩니다. 저장된 응답이 사라졌더라도(예: 24시간 기록이 만료) 같은 요청을 반복하면 Tahoe가 이전 발송을 찾아 그대로 반환하고, 아무것도 보내지 않으며 한도도 소모하지 않습니다. 이 확인은 수신 거부 확인보다 먼저 합니다. 첫 시도 뒤에 수신 거부한 사람에게도 거부되었다고 하지 않고 메시지가 발송되었다고 알려 주기 위해서입니다.
  • 오류로 끝난 요청은 키를 놓아 주므로 원인을 고친 뒤 같은 키로 다시 시도할 수 있습니다. 예외는 delivery_failed입니다. 같은 키는 같은 실패를 다시 알려 주며, 실패한 발송이 실수로 반복되지 않도록 한 설계입니다. 새 키로 다시 시도하세요.

오류

상태코드조치
400invalid_request본문 형식이 잘못되었거나, 필드가 너무 길거나, 제목에 줄바꿈이 있거나, 핸들을 둘 다 보냈거나 하나도 보내지 않았거나, email이나 reply_to처럼 이 엔드포인트가 받지 않는 필드가 있습니다. errors 목록에 필드가 표시됩니다.
400idempotency_key_requiredIdempotency-Key 헤더를 추가하세요.
400invalid_idempotency_key키가 허용된 문자 8~255자가 아닙니다.
403insufficient_scope키에 messages:send가 없습니다.
403write_requires_api_keySign in with Tahoe 토큰이거나, Tahoe 사용자와 연결되지 않은 자격 증명입니다.
404not_found지원서나 지원자가 키의 워크스페이스에 없습니다. 다른 워크스페이스의 핸들, 종류가 다른 핸들, 형식이 잘못된 핸들 모두 같은 응답을 받습니다.
409recipient_unsubscribed수신 거부했거나, 처리가 중단되었거나, 삭제되었거나, 메일을 받을 수 없는 주소입니다. 아무것도 보내지 않았습니다. 다시 시도하지 마세요.
409sender_email_missing키가 대신하는 Tahoe 사용자에게 이메일 주소가 없어 답장이 갈 곳이 없습니다.
409idempotency_key_reused같은 키를 이전에 다른 본문과 함께 썼습니다.
409idempotency_in_flight같은 키의 요청이 아직 실행 중입니다. 잠시 후 다시 시도하세요.
429rate_limit_exceeded분당 한도를 넘었습니다. Retry-After만큼 기다리세요.
429message_quota_exceeded키가 하루 최대치를 보냈습니다. Retry-After만큼 기다리세요.
429limiter_unavailable한도를 적용하는 카운터가 응답하지 못했습니다. 아무것도 보내지 않았습니다. Retry-After 뒤에 다시 시도하세요.
429datastore_unavailable데이터베이스나 수신 거부 기록이 응답하지 못했습니다. 아무것도 보내지 않았습니다. Retry-After 뒤에 다시 시도하세요.
429delivery_failed메일 제공자가 거부했거나 실패했습니다. 상대에게 아무것도 가지 않았습니다. 새 Idempotency-Key로 다시 시도하세요.

마지막 세 가지는 type: "unavailable"이며 503이 아니라 429를 씁니다. 이유는 429가 항상 요청 한도 초과는 아닙니다를 참고하세요. detail.code로 분기하세요.