Series 6 — Part 10 of 10
The relay pattern allows a client to ask the WhatsApp AI agent a question, the bot to forward it to the lawyer, the lawyer to reply via WhatsApp, and the bot to forward that reply to the client — all with a full audit trail. This article covers relay detection, forwarding, and the audit log requirements.
The Relay Flow
Client → the WhatsApp AI agent → [forwards to Lawyer] → Lawyer replies → the WhatsApp AI agent → [forwards to Client]
↑ ↑
│ AUDIT LOG │
└──────────────────── both sides logged with correlation ID ─────────────────┘
Forwarding a Client Question to the Lawyer
class RelayHandler
{
public function relayToLawyer(
string $clientQuestion,
int $matterId,
PersonaInterface $clientPersona,
PDO $pdo
): string {
$matter = get_matter_summary($matterId, $pdo);
$lawyer = get_assigned_lawyer($matterId, $pdo);
if (!$lawyer || !$lawyer['wa_number']) {
return "I'll need to check this with your lawyer. I'll follow up with you shortly.";
}
$relayMessage = "⚡ *Relay from the WhatsApp AI agent* ⚡\n\n"
. "*Matter:* " . $matter['ref_number'] . " — " . $matter['title'] . "\n"
. "*Client:* " . $clientPersona->getName() . "\n\n"
. "*Question:* " . $clientQuestion . "\n\n"
. "_Reply to this message to send your response to the client._";
$relayId = log_relay_sent($matterId, $clientPersona->getUserId(), $lawyer['id'],
$clientQuestion, $pdo);
send_whatsapp_text($lawyer['wa_number'], $relayMessage);
return "I've forwarded your question to " . $lawyer['full_name'] . ". "
. "They'll get back to you as soon as possible.";
}
public function detectRelayReply(string $lawyerMessage, int $lawyerUserId, PDO $pdo): ?array
{
// A relay reply starts with a specific marker or is in response to a relay
// Check if there's a pending relay for this lawyer in the last 48 hours
$stmt = $pdo->prepare(
'SELECT * FROM relay_log WHERE lawyer_id = ? AND status = \'pending\'
AND created_at > DATE_SUB(NOW(), INTERVAL 48 HOUR)
ORDER BY created_at DESC LIMIT 1'
);
$stmt->execute([$lawyerUserId]);
return $stmt->fetch() ?: null;
}
public function forwardReplyToClient(array $relay, string $lawyerReply, PDO $pdo): void
{
$client = get_user($relay['client_id'], $pdo);
$clientMessage = "📋 *Response from your lawyer:*\n\n" . $lawyerReply;
send_whatsapp_text($client['wa_number'], $clientMessage);
// Update relay log — both sides of the relay are now complete
$pdo->prepare(
'UPDATE relay_log SET status = \'completed\', lawyer_reply = ?, completed_at = NOW()
WHERE id = ?'
)->execute([$lawyerReply, $relay['id']]);
}
}
The Relay Audit Log
CREATE TABLE relay_log (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
team_id INT UNSIGNED NOT NULL,
matter_id BIGINT UNSIGNED NOT NULL,
client_id INT UNSIGNED NOT NULL,
lawyer_id INT UNSIGNED NOT NULL,
client_question TEXT NOT NULL,
lawyer_reply TEXT DEFAULT NULL,
status ENUM('pending','completed','expired') NOT NULL DEFAULT 'pending',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
completed_at DATETIME DEFAULT NULL,
wa_client_msg_id VARCHAR(255) DEFAULT NULL, -- traceability
wa_lawyer_msg_id VARCHAR(255) DEFAULT NULL
);
What to Watch For
- Relay expiry — If a lawyer doesn't reply within 48 hours, mark the relay as expired and notify the client that they should contact the office directly.
- Relay reply disambiguation — If a lawyer has multiple pending relays, the system needs to ask which one they're replying to. Use numbered references in the relay message if multiple are pending.
- Professional conduct — The relay creates an indirect communication channel. The lawyer must review the relayed question before it goes to the client, or the relay bypasses professional supervision. See S6-ADV6.