> Ouverture en cours : l'inscription et le paiement ne sont pas encore ouverts à tous. L'état du jour : https://subagent.fr/docs/etat.md
>
> Pour un agent : la carte du site est sur https://subagent.fr/llms.txt ; chaque page existe en Markdown, à la même adresse suffixée `.md`.

# `approve_message`

> Validation humaine : le brouillon passe en file et partira dans le créneau, selon les quotas.

## En bref

| Propriété | Valeur |
|---|---|
| Titre | Valider un brouillon |
| Outil MCP | `approve_message`, sur `https://api.subagent.fr/mcp` |
| Appel HTTP | `POST https://api.subagent.fr/v1/approve_message` |
| Accès | permission `approve` |
| État de l'espace | vérifié ou non |
| Effet | écriture |
| Vue dans l'assistant | non |

## Ce que fait l'outil

Le serveur décrit l'outil ainsi à l'agent qui se branche :

> Validation humaine : le brouillon passe en file et partira dans le créneau, selon les quotas. Réservé à une clé qui porte la permission approve (un humain dans son assistant) : un agent ne valide jamais ses propres envois. Refusé si le destinataire a été bloqué depuis la création. Donnez revision (lue dans `list_drafts`) : la validation est alors refusée si le brouillon a changé depuis sa lecture.

## Paramètres

`approve_message` accepte ces paramètres. Un paramètre inconnu est refusé avec le code `invalid_argument`.

| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| `message_id` | identifiant `msg_…` | oui | Le brouillon (msg_…, voir `list_drafts`). |
| `revision` | texte | non | La version du brouillon tel qu’il a été lu (champ revision de `list_drafts`). S’il a changé depuis, la validation est refusée (`draft_changed`). 32 caractères au plus. |

## Résultat

L'outil rend un message. L'objet structuré déclare les champs ci-dessous ; la page de concept les décrit tous : voir [les champs d'un message](https://subagent.fr/docs/messages.md#champs).

| Champ | Type | Contenu |
|---|---|---|
| `auto_reply` | booléen | Réponse automatique (absence…). |
| `created_at` | texte | ISO 8601. |
| `direction` | texte | `outbound` : sortant ; `inbound` : entrant. |
| `estimated_send_at` | texte ou `null` | Départ au plus tôt du message validé (estimation : créneau, étalement, quota). |
| `from` | texte | Expéditeur. |
| `has_html` | booléen | Le message a une version HTML. |
| `id` | texte | Identifiant du message (msg_…). |
| `inbox_id` | texte | Boîte du message. |
| `received_at` | texte ou `null` | La date de réception d'un message entrant (ISO 8601), sinon `null`. |
| `reply_to` | texte ou `null` | Adresse de réponse, si elle diffère de la boîte. |
| `revision` | texte | Version du message : change à chaque modification (voir `approve_message`). |
| `sent_at` | texte ou `null` | La date du départ (ISO 8601), sinon `null`. |
| `status` | texte | Le statut du message. Valeurs : `draft`, `queued`, `sending`, `sent`, `delivered`, `bounced`, `failed`, `rejected`, `cancelled`, `received`. |
| `status_code` | texte ou `null` | Code stable d’un refus ou d’un échec. |
| `subject` | texte | Sujet. |
| `text` | texte | Texte (lecture d’un message ou d’un fil). |
| `thread_id` | texte | Fil du message. |
| `to` | texte | Destinataire. |

## Exemple d'appel

Les valeurs sont fictives.

HTTP :

```sh
curl -X POST https://api.subagent.fr/v1/approve_message \
  -H "Authorization: Bearer $SUBAGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "message_id": "msg_7f2a91c4e8b34d0fa6c25e1b9d3f7a48",
  "revision": "1791892920417352"
}'
```

MCP (`tools/call`) :

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "approve_message",
    "arguments": {
      "message_id": "msg_7f2a91c4e8b34d0fa6c25e1b9d3f7a48",
      "revision": "1791892920417352"
    }
  }
}
```

## Refus possibles

| Code | HTTP | Ce qui s'est passé | Que faire |
|---|---|---|---|
| `not_found` | 404 | L'objet n'existe pas pour cette clé. | Vérifier l'identifiant : il vient de `list_inboxes`, `list_threads`, `get_thread` ou `list_drafts`. |
| `not_draft` | 409 | Le message n'est pas, ou n'est plus, un brouillon. | Relire son statut avec `get_message`. |
| `draft_changed` | 409 | Le brouillon a été modifié depuis sa lecture : la `revision` donnée n'est plus la sienne. | Relire le brouillon avec `list_drafts`, puis valider la version lue. |
| `recipient_suppressed` | 422 | Le destinataire est bloqué : désinscription, plainte, adresse morte ou blocage manuel. | Ne plus écrire à cette adresse, depuis aucune boîte. |
| `payment_required` | 402 | L'espace n'a pas de forfait en cours : sa boîte reçoit, prépare des brouillons et n'écrit qu'à son humain. Le refus vaut pour un envoi à un tiers, la validation d'un brouillon, une seconde boîte et `add_domain`. | Appeler `subscribe`, après l'accord de l'humain, et lui remettre le lien de paiement. Ensuite, `billing_status` dit si le forfait est en cours. |
| `own_domain_required` | 422 | La boîte est sur le domaine commun : elle ne fait que répondre à qui lui a écrit. Un premier message, ou une relance sans réponse, n'en part pas. | Enregistrer le domaine de l'humain (`add_domain`), le faire vérifier (`verify_domain`), y créer une boîte (`create_inbox`) et écrire depuis elle. |

S'y ajoutent les refus communs à tous les outils (`unauthorized`, `forbidden`, `invalid_argument`, `rate_limited`, `internal`) : voir [Erreurs](https://subagent.fr/docs/erreurs.md#acces).

## Voir aussi

- [Brouillons et validation : approve_message](https://subagent.fr/docs/brouillons.md#approve_message)
- [Guide : valider les envois d'un agent](https://subagent.fr/docs/guide-validation.md)
- [`list_drafts`](https://subagent.fr/docs/reference/list_drafts.md)
- [`update_draft`](https://subagent.fr/docs/reference/update_draft.md)
- [`cancel_message`](https://subagent.fr/docs/reference/cancel_message.md)
- [Tous les outils](https://subagent.fr/docs/reference/index.md)
