A recipient is created the first time you push to an address. There is no create operation and no import, which is the structural reason BeaconBox cannot be used for marketing: you can only message somebody you have already sent an order update to.
Recipients are scoped to your business. Another merchant messaging the same person sees a different recipient with its own number, its own consent and its own history.
Reading one
curl https://api.beaconbox.eu/api/v1/recipients/buyer@example.com/sms \
-H "Authorization: Bearer $BEACONBOX_API_KEY"from beaconbox import RecipientStatus
sms = client.recipients.sms("buyer@example.com")
print(sms.phone) # "+372 •••• 0134", masked
print(sms.sms_status) # none, active, or stopped
if sms.sms_status == RecipientStatus.STOPPED:
pass # they texted STOP. Holds until they text START.use BeaconBox\Enum\RecipientStatus;
$sms = $client->recipients->sms('buyer@example.com');
echo $sms->phone; // "+372 •••• 0134", masked
echo $sms->smsStatus->value ?? $sms->smsStatus; // none, active, or stoppedsms_status is none (no consent recorded either way), active, or stopped. There is no
boolean: none and stopped mean different things, and a flag would collapse “we have never been
told” into “they said no”.
sms_consent_at and sms_consent_source say when and how the recipient first became textable:
the moment a number was first accepted for them, and the route it came in on (push for
recipient_phone on a push, api for PUT /recipients/{email}/phone, admin for the dashboard’s
recipient page). They are written once and never change, so a new number, a STOP and a later START
all leave the original. Both are null for a recipient who has never had a number, or whose number
was set before these fields existed.
Texting START lifts only a stop they texted. A stop they made in their inbox, or one recorded from the dashboard, is not lifted by a text.
Setting and clearing a number
curl -X PUT https://api.beaconbox.eu/api/v1/recipients/buyer@example.com/phone \
-H "Authorization: Bearer $BEACONBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone": "+37255550134"}'
curl -X DELETE https://api.beaconbox.eu/api/v1/recipients/buyer@example.com/phone \
-H "Authorization: Bearer $BEACONBOX_API_KEY"client.recipients.set_phone("buyer@example.com", "+37255550134")
client.recipients.clear_phone("buyer@example.com")$client->recipients->setPhone('buyer@example.com', '+37255550134');
$client->recipients->clearPhone('buyer@example.com');Neither needs an Idempotency-Key: setting a number twice leaves one number, and clearing it
twice leaves it cleared. Sending the header anyway is harmless.
The two erasures below are the operations on this page that do require it.
Three rules worth knowing before you write a sync job:
- A number held by another of your recipients is refused with
sms.phone_already_in_use, rather than moved. The usual cause is a typo, and the cost of guessing is texting the wrong person about somebody else’s order. - Clearing a number does not clear an opt-out. Somebody who texted
STOPstays stopped. An opt-out is about a person, not about a number you happen to be holding. - Changing a number does clear WhatsApp consent. That consent is permission to message a particular number, so it cannot survive the number changing.
Erasing WhatsApp history
For a customer exercising a right to erasure.
curl -X POST https://api.beaconbox.eu/api/v1/recipients/buyer@example.com/whatsapp/erase \
-H "Authorization: Bearer $BEACONBOX_API_KEY" \
-H "Idempotency-Key: 9c3a7f20-5e84-4b11-a6d9-0f72cb48e551"receipt = client.recipients.erase_whatsapp("buyer@example.com")
# The half only you can finish: erased replies whose words may already be
# sitting in your own mailboxes, from forwards we sent you.
yours = receipt.replies_a_forward_email_may_have_carried
if yours:
log.warning("%d forwarded replies to find in our own mail", yours)$receipt = $client->recipients->eraseWhatsApp('buyer@example.com');
// The half only you can finish.
$yours = $receipt->repliesAForwardEmailMayHaveCarried;
if ($yours > 0) {
$log->warning("{$yours} forwarded replies to find in our own mail");
}WhatsApp replies are deleted after 90 days regardless, so this is for doing it now rather than for doing it at all.
Erasing a recipient
For a customer asking you to erase everything about them, POST /recipients/{email}/erase deletes
what BeaconBox holds about that person for your business: every update you sent them, with its
delivery history and any WhatsApp replies; their number and consent; and their address inside
anything still queued to your webhook endpoint. It includes the WhatsApp erasure above, so one call
is enough. It cannot be undone.
It keeps exactly what stops them being contacted again, because an erasure that forgot those would undo itself: a bounce or complaint against the address, and an opt-out against the number. Those hold an identifier and a reason, never content.
Four things worth knowing:
- The address must be an address. Every
{email}in a path on this page is validated the way a push’srecipient_emailis, and normalised the way it is stored (trimmed, lower case). Anything else, a blank or a single letter included, is a422before anything runs, so a bug in your own code cannot turn an erasure into a wildcard. - It is scoped to your business. Another merchant who messaged the same person keeps their own records, and the response never says whether one exists.
- The response counts what was deleted, table by table, and erasing again answers zeros. An address you never messaged also answers zeros, so the call says nothing about who is on your list.
- Your own copies are yours to erase. Anything your webhook receiver stored, and forwarded WhatsApp replies in your mailboxes, are outside our reach.
Send an Idempotency-Key, as with the WhatsApp erasure. The SDK methods are listed in the
API reference.
A push to an erased address afterwards starts a new recipient from nothing: no history and no opt-out state, except the bounce, complaint or STOP that was kept.
