Record a preference
/v1/preferencesconst result = await bird.preferences.create({
channel: "sms",
handle: "+15550001234",
status: "revoked",
});
console.log(result.applied, result.preference?.id);result = client.preferences.create(
channel="email",
handle="jane@acme.com",
status="granted",
consented_at="2026-08-20T14:03:10Z",
source="signup-form-v2",
)
if result.preference:
print(result.applied, result.preference.id)result, err := client.Preferences.Create(context.Background(), bird.PreferencesCreateParams{
Channel: bird.PreferenceChannelEmail,
Handle: "recipient@example.com",
Status: bird.PreferenceStatusGranted,
Source: "signup-form-v2",
ConsentedAt: time.Now(),
})
if err != nil {
log.Fatal(err)
}
// A newer statement already on file answers Applied false instead of an
// error, with the surviving statement in Preference.
if result.Applied != nil && *result.Applied {
fmt.Println("grant recorded")
}$result = $bird->preferences->create(
channel: 'email',
handle: 'jane@acme.com',
status: 'granted',
source: 'signup-form-v2',
consentedAt: new DateTimeImmutable('2026-08-20T14:03:10Z'),
);
echo var_export($result->getApplied(), true);bird preferences create \
--channel sms \
--coverage non_transactional \
--handle +15550001234 \
--status revokedcurl -X POST "https://us1.platform.bird.com/v1/preferences" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel": "sms",
"handle": "+15550001234",
"status": "revoked",
"coverage": "non_transactional"
}'{
"transition_id": "prt_01krdgeqcxet5s7t44vh8rt9mg",
"preference": {
"id": "prf_01krdgeqcxet5s7t44vh8rt9mg",
"channel": "sms",
"handle": "+15550001234",
"sender_scope": "+15557654321",
"topic_id": null,
"status": "revoked",
"coverage": "non_transactional",
"origin": "api_key",
"source": "signup-form-v2",
"contact_id": "con_01krdgeqcxet5s7t44vh8rt9mg",
"created_at": "2026-05-20T09:14:52Z",
"updated_at": "2026-05-25T16:42:01Z"
}
}
Records one statement, a grant or an opt-out, for a handle on one channel. Writing is an upsert: the key is the channel, handle, and optional sender scope, and a new statement replaces the key's current one.
Statements are ordered by when they were made, not when they arrive. A statement older than the key's current one is refused and returned with applied: false alongside the statement that survived; refusals are recorded on the key's history. Granting over a stored opt-out needs consented_at later than the opt-out, and a person's own opt-out (an unsubscribe, a stop keyword) cannot be overridden by a grant asserted on their behalf.
A 201 means this key had no record and one was created; a 200 returns the key's surviving record, whether this statement replaced it, repeated it, or was refused.
请求载荷
handleWho the statement is about: an email address on the email channel, a phone number in E.164 format on SMS, WhatsApp, and Apple Messages for Business.
channelThe channel a preference statement applies to. A preference addresses one channel: the handle that identifies the person differs per channel, so opting out of one channel says nothing about the others. New channels can be added over time, so a value outside this list can be returned.
Possible values (may grow over time): email, sms, whatsapp, amb
statusWhat the statement says: granted records consent to receive messages, revoked records an opt-out. There is no third state: a person who never stated anything simply has no preference on record.
Possible values: granted, revoked
coverageHow much traffic the statement covers. Defaults to non_transactional, which keeps transactional messages such as receipts and verification codes flowing. Apple Messages for Business phone invitations have no transactional exemption, so either value covers them.
sender_scopeLimit the statement to one sender instead of the whole channel. On SMS this is the originator; on WhatsApp it identifies the business account; on Apple Messages for Business it is the Apple business ID used for invitations. Not supported on email, where preferences are always channel-wide.
sourceFree-form note on where the statement came from: a form name, an import batch, a campaign. Stored verbatim and returned on the preference.
consented_atWhen the person consented, on a granted statement. Required evidence when granting over a stored opt-out: the grant applies only if this is later than the opt-out it reverses. May not be in the future.
响应载荷
appliedWhether the request took effect. False only when it was refused as out of order; the surviving, newer statement is returned in preference.
transition_idIdentifies this write on the key's record, for applied and refused requests alike. Null when the write was a repeat of the current statement and recorded nothing new.
preferenceThe key's surviving statement. Null after an applied delete, when the key is back to having no record.