POST /api/v1/series
Crée la série et le brouillon de sa version 1, en une seule transaction. Répond 201.
C'est la route que POST /api/v1/sequences refuse : là-bas, triggerType: "fixed_date" renvoie 400, parce qu'une série a besoin de son audience et de sa date de départ dans le même appel. Ici, le déclencheur est imposé — envoyer un autre triggerType dans le corps ne change rien.
Autorisation
| Rôle | Accès |
|---|---|
OWNER | Autorisé |
ADMIN | Autorisé |
MEMBER | Refusé — 403 |
Corps de la requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
name | string | Oui | De 1 à 100 caractères |
listId | string (uuid) | Oui | La liste à laquelle la série envoie |
startsAt | string (ISO 8601) | Non | Le jour 1. Facultatif ici — une série se crée puis se programme — et obligatoire à la publication |
audienceSegmentId | string (uuid) | Non | Restreint la liste |
audienceTagId | string (uuid) | Non | La restreint davantage |
json
{
"name": "March launch",
"listId": "9f8e7d6c-1111-4bbb-8ccc-ddddeeeeffff",
"startsAt": "2026-03-15T08:00:00.000Z",
"audienceSegmentId": null,
"audienceTagId": null
}Exemple
bash
curl -s -X POST 'https://www.agentsmail.io/api/v1/series' \
-H "x-api-key: $AGENTMAIL_API_KEY" \
-H 'content-type: application/json' \
-d '{
"name": "March launch",
"listId": "9f8e7d6c-1111-4bbb-8ccc-ddddeeeeffff",
"startsAt": "2026-03-15T08:00:00.000Z"
}'Réponse
| Code | Quand |
|---|---|
201 | La série et le brouillon de sa version 1 existent |
400 | Corps invalide, ou startsAt n'est pas une date lisible |
401 | Clé absente ou invalide |
403 | Le rôle de la clé est MEMBER |
Champs de la réponse
Même forme que lister les séries, pour l'objet unique contenu dansdata.
Exemple de réponse
json
{
"success": true,
"data": {
"id": "7d7d7d7d-8888-4ccc-9ddd-eeee00001111",
"name": "March launch",
"status": "paused",
"startsAt": "2026-03-15T08:00:00.000Z",
"listId": "9f8e7d6c-1111-4bbb-8ccc-ddddeeeeffff",
"audienceSegmentId": null,
"audienceTagId": null,
"topicId": null,
"createdAt": "2026-03-01T10:00:00.000Z",
"updatedAt": "2026-03-01T10:00:00.000Z"
}
}Recette pour agent
Créer la série est la première de quatre étapes — à elle seule, elle n'envoie rien. L'identifiant renvoyé est un identifiant de séquence, et les étapes s'ajoutent par l'API Séquences.js
const headers = {
'x-api-key': process.env.AGENTMAIL_API_KEY,
'content-type': 'application/json',
}
const api = 'https://www.agentsmail.io/api/v1'
// 1. The series, with its audience and its start date
const {data: series} = await fetch(`${api}/series`, {
method: 'POST',
headers,
body: JSON.stringify({name: 'March launch', listId, startsAt: '2026-03-15T08:00:00.000Z'}),
}).then((r) => r.json())
// 2. Its version 1 draft already exists — find it
const {data: versions} = await fetch(`${api}/sequences/${series.id}/versions`, {
headers,
}).then((r) => r.json())
const draft = versions.find((v) => v.status === 'draft')
// 3. The steps, on the Sequences API — in TWO calls each for a send.
// Creating a node only takes its `type` (plus `waitHours` on a wait, or
// `templateId` to start from a template): a new send step is born with the
// default content and no subject. The subject, the content and the send
// time are written by a PATCH on the node that comes back.
const nodes = `${api}/sequences/${series.id}/versions/${draft.id}/nodes`
const addNode = (body) =>
fetch(nodes, {method: 'POST', headers, body: JSON.stringify(body)})
.then((r) => r.json())
.then((r) => r.data)
const editNode = (id, body) =>
fetch(`${nodes}/${id}`, {method: 'PATCH', headers, body: JSON.stringify(body)})
.then((r) => r.json())
.then((r) => r.data)
// One PATCH per FAMILY: the subject and the content are one family, the send
// time is another, and sending two families in a single call is refused.
const teaser = await addNode({type: 'send_email'})
await editNode(teaser.id, {subject: 'Something is coming', content: html})
// The time of day, in minutes from midnight. Leave it out and the step goes
// out as soon as the wait before it has elapsed.
await editNode(teaser.id, {sendTimeMinutes: 540})
// A wait gives the DURATION between two sends.
await addNode({type: 'wait', waitHours: 72})
const launch = await addNode({type: 'send_email'})
await editNode(launch.id, {subject: 'It is here', content: html2})
await editNode(launch.id, {sendTimeMinutes: 540})
// 4. Publish. This is where a series without a start date is refused, by name.
await fetch(`${api}/sequences/${series.id}/versions/${draft.id}/publish`, {
method: 'POST',
headers,
}).then((r) => r.json())Remarques
Une nouvelle série estpaused. L'activer se fait par un PATCH avec {"status": "active"}, refusé tant qu'aucune version n'est publiée.