Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 88 additions & 15 deletions source/includes/rest/_broadcasts.md
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ Rate limits are applied per user.

## Set the audience

> To send a Single-Email Campaign to a saved segment:
> To send a Single-Email Campaign to a saved segment, leaving out people with either of two tags:

```shell
curl -X PUT "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/audience" \
Expand All @@ -958,7 +958,10 @@ curl -X PUT "https://api.getdrip.com/v2/YOUR_ACCOUNT_ID/broadcasts/BROADCAST_ID/
-u YOUR_API_KEY: \
-d '{
"filter": [
[{ "type": "segments", "properties": { "operator": "in", "segment_id": "4815162" } }]
[
{ "type": "segments", "properties": { "operator": "in", "segment_id": "4815162" } },
{ "type": "tags", "properties": { "operator": "not_include_any", "value": ["Churned", "Refunded"] } }
]
]
}'
```
Expand All @@ -975,7 +978,10 @@ request["User-Agent"] = "Your App Name (www.yourapp.com)"
request["Content-Type"] = "application/vnd.api+json"
request.body = {
filter: [
[{ type: "segments", properties: { operator: "in", segment_id: "4815162" } }]
[
{ type: "segments", properties: { operator: "in", segment_id: "4815162" } },
{ type: "tags", properties: { operator: "not_include_any", value: ["Churned", "Refunded"] } }
]
]
}.to_json

Expand All @@ -998,7 +1004,10 @@ const response = await fetch(
},
body: JSON.stringify({
filter: [
[{ type: "segments", properties: { operator: "in", segment_id: "4815162" } }]
[
{ type: "segments", properties: { operator: "in", segment_id: "4815162" } },
{ type: "tags", properties: { operator: "not_include_any", value: ["Churned", "Refunded"] } }
]
]
})
}
Expand Down Expand Up @@ -1060,14 +1069,73 @@ true of a person, and a person matching any inner list is included. So
`[[A, B], [C]]` means "(A and B) or C".

`[[]]` means everyone eligible to receive it, and is how you clear an audience. An empty
filter, `[]`, is rejected.
filter, `[]`, is rejected. A filter takes at most 10 AND-sets, each with at most 10 conditions.

Two condition types are available: `segments` and `tags`. Each condition is a `type` and a
`properties` object holding the `operator` and its value. More condition types will follow.

A `segments` condition takes the operator `in` or `not_in` and a `segment_id`, which is the `id`
from the Segments API. `segment_id` takes one id, never a list: `["4815162"]` is rejected. For
several segments, use one condition each. Two conditions in the same inner list mean "in both";
two in separate inner lists mean "in either".

Today the only condition type available is `segments`, with the operators `in` and
`not_in`. The `segment_id` is the `id` from the Segments API. More condition types will follow.
A `tags` condition takes one of the operators below and a `value`. Name a tag as the Tags API
returns it; matching ignores case and repeated spaces. A tag does not have to exist on the
account yet: a condition naming a tag no one has matches no one, or everyone when negated.

<table>
<thead>
<tr>
<th>Operator</th>
<th><code>value</code></th>
<th>Matches people who</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>include</code></td>
<td>One tag, as a string</td>
<td>have the tag</td>
</tr>
<tr>
<td><code>not_include</code></td>
<td>One tag, as a string</td>
<td>do not have the tag</td>
</tr>
<tr>
<td><code>contains</code></td>
<td>Text, as a string</td>
<td>have a tag whose name contains the text</td>
</tr>
<tr>
<td><code>include_any</code></td>
<td>A list of tags</td>
<td>have at least one of the tags</td>
</tr>
<tr>
<td><code>include_all</code></td>
<td>A list of tags</td>
<td>have every one of the tags</td>
</tr>
<tr>
<td><code>not_include_any</code></td>
<td>A list of tags</td>
<td>have none of the tags</td>
</tr>
<tr>
<td><code>not_include_all</code></td>
<td>A list of tags</td>
<td>are missing at least one of the tags</td>
</tr>
<tr>
<td><code>no_tags</code></td>
<td>Omitted, or <code>""</code></td>
<td>have no tags at all</td>
</tr>
</tbody>
</table>

`segment_id` takes one id, never a list: `["4815162"]` is rejected. For several segments, use
one condition each. Two conditions in the same inner list mean "in both"; two in separate
inner lists mean "in either".
A blank tag, an empty list, or a blank entry in a list is rejected.

Replacing an audience requires `confirm=true` whenever the current audience is anything other
than everyone, because what is being replaced cannot be recovered through the API. Read the
Expand Down Expand Up @@ -1137,7 +1205,10 @@ const body = await response.json();
{
"audience": {
"filter": [
[{ "type": "segments", "properties": { "operator": "in", "segment_id": "4815162" } }]
[
{ "type": "segments", "properties": { "operator": "in", "segment_id": "4815162" } },
{ "type": "tags", "properties": { "operator": "not_include_any", "value": ["Churned", "Refunded"] } }
]
]
}
}
Expand All @@ -1149,19 +1220,21 @@ const body = await response.json();
{
"audience": {
"message": "This filter includes unsupported criteria and cannot be returned as a filter.",
"summary": "People who are tagged with \"vip\"",
"unsupported_types": ["tags"]
"summary": "People who have performed \"Purchased VIP\"",
"unsupported_types": ["actions"]
}
}
```

`filter` comes back in the same shape it is set in, so reading an audience and writing it
straight back changes nothing.

`filter` is present only when writing it again would be accepted. Most audiences built in the
`filter` is present only when writing it again would be accepted. Many audiences built in the
Drip app use rules that have no form here yet, and those come back described instead:
`summary` is plain-English display text, and `unsupported_types` names the condition types in
the way. Expect that until more condition types are available.
the way. Expect that until more condition types are available. If every condition type is
available but the filter still cannot be returned, for example because of its size,
`unsupported_types` is left out.

A present `filter` is not a promise that its segments still exist. That is not checked on
read, so an audience naming a segment deleted since it was set reads back intact and responds
Expand Down
Loading