Send as a human agent

Past the 24 hour window there is exactly one way to reach a person: a message typed by a named human, sent on the human-agent route, within 7 days of their last message. There is no generic send and there are no message tags.

When to use it#

The route is for a real person following up on a real thread: a delayed answer, a question that needed research, a booking confirmation that came through after hours. It is not a broadcast channel and it cannot be automated, which is a policy HookChat enforces rather than a setting you can change.

Send as a named human#

The request is the reply request plus actor_id, the identity of the person who wrote the message. Use whatever identifies them in your own system: a user id, an agent handle, a console session. It is recorded in the audit trail and on the message as actor_id.

TypeScript
import { HookChat } from '@hookchat/node'

const client = new HookChat({ apiKey: process.env.HOOKCHAT_API_KEY!, baseUrl: process.env.HOOKCHAT_BASE_URL! })

// actor_id is required by the type: omitting it does not compile.
const { platform_message_id } = await client.messages.sendAsHumanAgent({
  conversation_id: process.env.CONVERSATION_ID!,
  text: 'Sorry for the delay, following up personally.',
  actor_id: 'agent-7',
})
console.log('sent', platform_message_id)

The success shape is identical to the reply route: { ok: true, data: { platform_message_id } }. Attachments and reply_to work the same way too.

Past seven days#

When the conversation is closed the route refuses with human_agent_unavailable (409). Nothing exists past 7 days on any platform; the right move is to wait for the participant to write again, which reopens the 24 hour window.

TypeScript
import { HookChat, HookChatError } from '@hookchat/node'

const client = new HookChat({ apiKey: process.env.HOOKCHAT_API_KEY!, baseUrl: process.env.HOOKCHAT_BASE_URL! })

try {
  await client.messages.sendAsHumanAgent({
    conversation_id: process.env.CLOSED_CONVERSATION_ID!,
    text: 'Checking in',
    actor_id: 'agent-7',
  })
} catch (error) {
  if (error instanceof HookChatError && error.code === 'human_agent_unavailable') {
    console.log('refused:', error.code)
  } else {
    throw error
  }
}

Why actor_id is required#

A human-agent message is human-sent by definition, so the gateway refuses one that names nobody with missing_actor (409). That is a policy refusal, not a validation error: the body was well formed, the request was simply not allowed. The SDKs make the mistake hard to write: the TypeScript type requires the field, the Python method takes it as a required keyword, and the Go client refuses an empty ActorID locally with the same code.

Do not put a service name or a bot id in actor_id to get an automated follow-up through. The route exists because a real person must stand behind an out-of-window message, and the audit trail records who that was.

Errors the human-agent route returns#

codeHTTPMeaning
invalid_request400Malformed body, no conversation_id, or no text and no attachments.
unauthorized401Missing or invalid bearer key.
conversation_not_found404No such conversation. A cross-tenant id is a 404, never a 403.
missing_actor409No actor_id. The human who sent it must be named.
human_agent_unavailable409The conversation is past the 7 day window.
rate_limited409The account's send budget for this category is spent.
send_failed502Policy allowed the send and Meta or the network refused it. A retry can help.

Next#