Skip to main content

Adding existing guests to a list and sending campaigns from your own site

How to bulk-add guests who already exist in Bookboost to a list, how to fire a specific campaign from your own code, and which other endpoints are available.

Not every signup is a new guest, and not every message is triggered by a signup. Two further requests cover the rest: one adds guests who already exist to a list, and one sends a campaign at a moment only your own system knows about, such as a voucher being redeemed. Both use the same API key and the same base address as Connecting your website signup form to Bookboost.

Adding guests you already have to a list

Use this when you are migrating an existing subscriber list, or bulk-adding guests you already hold. Unlike store-in-list, which takes an email address, this one works only on profiles that already exist and is addressed by profile UUID. It takes up to 100 per request.

Update User is the third member of this family, and also requires an existing profile UUID. Use it to change consent on a guest you already have without touching list membership.

POST https://cdp.bookboost.io/api/v1/users/add-to-list

{
  "list_id": "e0249634-e67f-3fb4-9a9b-d8dcbe43ced8",
  "consent_id": "7c1f0a52-1d4e-4a55-9f2b-3c8d5e6a7b90",
  "users": [
    "9ab39d32-7f65-31bc-8b16-31a1b827246e",
    "8a47a49e-bc81-3ec1-bf5f-0492d55068f6"
  ]
}

Here consent_id is optional, and the choice matters:

  • Include it and the same consent behaviour applies to everyone in the batch, including sending confirmation emails. Be careful with large batches, because a batch of 100 against a consent with Require Confirmation on sends 100 confirmation emails.

  • Leave it out and only list membership changes. No permission is touched.

Sending a specific campaign from your own code

Sometimes the moment worth messaging about is one only your systems know about: a form was submitted, a voucher was redeemed, a booking was made on your own site. Build the campaign with the After external trigger (API) trigger, give it a slug, and call it by that slug.

POST https://cdp.bookboost.io/api/v1/trigger-campaign

{
  "campaign": "voucher-redeemed",
  "email": "maria@example.com",
  "payload": {
    "voucher_code": "SPRING25",
    "discount": "25%"
  }
}

Field

Required

Notes

campaign

Yes

The campaign slug, not its name or ID

email or phone

One of them

Identifies an existing profile

reservation

No

A booking reference, which makes reservation data available in the template

timestamp

No

ISO datetime, and it must be in the future. Leave it out to send now

payload

No

A flat key and value object, one level deep. Available in templates as message_payload

Three constraints catch people out:

  • The profile has to exist already. This request does not create it. If it is missing you receive 422 with "User with email ... not found." If the guest may be new, send users/store-in-list first.

  • The campaign has to be published, and it has to be a Journey campaign rather than a Broadcast. Otherwise you receive 404.

  • There is a cap of two API-triggered sends per campaign, per profile, per day. Beyond that you receive 422. The cap exists so that a retry loop cannot send a guest the same message repeatedly.

Other endpoints you may need

All paths are relative to https://cdp.bookboost.io and all require Authorization: Bearer YOUR_API_KEY.

Method and path

What it does

POST /api/v1/users/store-in-list

Create a profile, add it to a list, and record consent. The signup request

POST /api/v1/users/add-to-list

Add up to 100 existing profiles to a list, optionally with a consent. Requires profile UUIDs

GET /api/v1/users-list

All your lists. An alternative to reading the UUID from Profiles > Lists

GET /api/v1/users-list/{uuid}

One list

POST /api/v1/users-list

Create a list. Body: name, which must be unique in your organisation

PUT /api/v1/users-list/{uuid}

Rename a list

DELETE /api/v1/users-list/{uuid}

Delete a list

POST /api/v1/user/{user_uuid}/unsubscribe

Revoke consents. Body: consents as an array of UUIDs, or all: true

POST /api/v1/trigger-campaign

Send a campaign that uses the After external trigger (API) trigger

GET /api/v1/campaign-metrics?campaign={slug}&start=&end=

Sends, opens, clicks, and opt-ins for a campaign

POST /api/v1/email-message

Send one plain email to an existing profile. Body: email, subject, body. No templating

POST /api/v1/sms-message

Send one plain SMS to an existing profile. Body: phone, body

/api/v1/user-tags...

Manage tags and attach them to profiles

When to use email-message rather than trigger-campaign

email-message sends a subject and body you compose yourself. There are no merge fields, no branding, and no fallback to another channel. It suits internal or transactional one-offs. If you want a designed, personalised message that can reach the guest on more than one channel, build it as a campaign with the After external trigger (API) trigger and use trigger-campaign instead.

Unsubscribing

POST /api/v1/user/{uuid}/unsubscribe revokes consents that are currently granted or implicit. Consents already at pending or revoked are skipped silently and the request still succeeds, so a success response does not confirm that anything changed.

Revoking consent does not remove the guest from any list, and removing them from a list does not revoke consent. If unsubscribe means both to you, do both.

Which API version to use

Bookboost also has a CDP Public API v3 at /cdp/public/v3/..., on the same cdp.bookboost.io host but with a different authentication model and a richer profile structure. It covers profiles, lists, reservations, and loyalty, but it does not cover consent or campaigns.

For the signup and confirmation flow described here, use the v1 endpoints. If you are already using v3 for profiles or reservations, the two can run alongside each other on separate keys.

Getting help

Open Help at the bottom of the left menu and choose Talk to Us, or email support@bookboost.io. Include the endpoint, the response status code, and the response body. Full endpoint details are in the API Reference.

Did this answer your question?