Appearance
Subscriptions
Full reference for the Subscriptions resource in the bluefox.email API. See the API overview for authentication, the response envelope, and pagination.
List subscribers of a list
GET /v1/subscriber-lists/{id}
Legacy flat URL shape. Auth: API key (Authorization: Bearer) matching the list's project, OR an admin/account-owner JWT.
Unlike GET /v1/projectId/{projectId}/contacts (where custom field values are flat top-level keys), here they are
returned nested under a "customFields" object, e.g. { "email": "x@y.com", "customFields": { "plan": "pro" } }.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The subscriber list _id. |
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 403 | Missing or invalid API key |
Response body
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object | ||
items[].email | string | ||
items[].status | string (unverified | active | unsubscribed | paused) | ||
items[].customFields | object | Custom contact field values, keyed by field name. | |
count | integer | Total matching items across all pages, not just this page. | |
next | string | Full URL (path + query string) of the next page, or null if this is the last page. |
Subscribe a contact to a list
POST /v1/subscriber-lists/{id}
Legacy flat URL shape. Creates the contact if it doesn't exist yet. Auth: API key, or a whitelisted Origin (in which case a CAPTCHA is required unless the list disables it).
Double opt-in: when it is on for the list and the request uses an API key (or a whitelisted Origin), a new contact - or one who is unverified or unsubscribed on the list - is not activated. They get the verification email and stay as they are (new contacts become "unverified") until they click its link, and the response is { success: true, info } instead of the subscriber. Sending status "active" does not skip this. A paused subscriber is reactivated directly, without an email. With a SubscriptionToken the subscriber has already proven they own the address, so they are activated directly.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The subscriber list _id. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | yes | |
name | string | ||
status | string (unverified | active) | ||
captchaText | string | ||
captchaProbe | string |
Responses
| Status | Description |
|---|---|
| 201 | Created |
| 400 | Invalid request body or query - every violation found (missing/invalid/unexpected fields) is reported in one response, semicolon-separated, not just the first one hit. |
| 403 | Missing or invalid API key |
| 405 | The operation is blocked by a business rule (e.g. the resource is still in use) |
Response body
| Field | Type | Required | Description |
|---|---|---|---|
status | string | ||
email | string |
Get a subscriber by email
GET /v1/subscriber-lists/{id}/{email}
Legacy flat URL shape. Accepts an API key or a whitelisted Origin header.
Unlike GET /v1/projectId/{projectId}/contacts/{email} (where custom field values are flat top-level keys), here they
are returned nested under a "customFields" object, e.g. { "email": "x@y.com", "customFields": { "plan": "pro" } }.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The subscriber list _id. |
email | path | string | yes |
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 403 | Missing or invalid API key |
| 404 | Subscriber not found |
Response body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ||
status | string (unverified | active | unsubscribed | paused) | ||
customFields | object | Custom contact field values, keyed by field name. |
Update a subscriber (status, contact fields, pause/resubscribe)
PATCH /v1/subscriber-lists/{id}/{email}
Legacy flat URL shape. Setting status to "paused" requires pausedUntil (a future date). Accepts an API key or a whitelisted Origin header.
Double opt-in: when it is on for the list and the request uses an API key, setting status to "active" on an unverified or unsubscribed subscriber does not activate them - they keep their status, get the verification email, and the response includes verificationEmailSent: true. They become active only by clicking its link. A paused subscriber is reactivated directly. With a SubscriptionToken the change applies directly.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The subscriber list _id. |
email | path | string | yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ||
status | string (active | paused | unsubscribed) | ||
pausedUntil | string |
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 400 | Invalid request body or query - every violation found (missing/invalid/unexpected fields) is reported in one response, semicolon-separated, not just the first one hit. |
| 403 | Missing or invalid API key |
| 404 | Subscriber not found |
| 405 | The operation is blocked by a business rule (e.g. the resource is still in use) |
One-click unsubscribe
POST /v1/subscriber-lists/{id}/{email}/unsubscribe
Legacy flat URL shape. Not API-key authenticated - requires a signed one-click-unsubscribe token (the ?token= query param from a dispatched email's List-Unsubscribe link).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The subscriber list _id. |
email | path | string | yes | |
token | query | string | yes |
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 403 | Missing or invalid API key |
| 404 | Subscriber not found |
Look up a published, BlueFox-hosted signup form by its public slug
GET /v1/signup-forms/slug/{slug}
Not API-key authenticated - requires a whitelisted Origin header instead, restricted to BlueFox's own app domain (the APP_URL this deployment is configured with) since this endpoint only ever backs the bluefox.email/signup/{slug} page and takes no project-level whitelist. Only returns forms with published: true (404 otherwise, including for a valid slug on an unpublished form). Returns the same self-contained, ready-to-render HTML (styling, markup, and captcha/submit JS included) as GET .../signup-forms/{id}/embed - never the raw form config, so there is no secret-leak surface. Also includes the owning project's name and logoUrl for page branding.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
slug | path | string | yes |
Responses
| Status | Description |
|---|---|
| 200 | OK |
| 403 | Missing or invalid API key |
| 404 | Signup form not found |
Response body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ||
pageHeadline | string | The heading to show on the hosted page. Falls back to the project name when not set. | |
pageDescription | string | The description to show under the heading on the hosted page. | |
formLayout | string | The form's layout ("row" or "column") - the hosted page uses this to size its own container appropriately, since a row-laid-out form needs more width than a column one. | |
html | string | ||
project | object | ||
project.name | string | ||
project.logoUrl | string |
Submit a hosted/embedded signup form
POST /v1/signup-forms/{id}
Legacy flat URL shape. Not API-key authenticated - requires a whitelisted Origin header (BlueFox's own hosted-page domain is always allowed), and (depending on the form config) a CAPTCHA. Subscribes the contact to every list configured on the form.
Double opt-in follows the form's own setting, not the lists': when it is on, lists where the contact is new, unverified or unsubscribed get one verification email covering all of them (response { success: true, info }, statuses unchanged until the link is clicked); lists where they are paused are reactivated directly; lists where they are already active are skipped, and if that is every list the request fails with 400 "Email already exists.".
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | The signup form _id. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | yes | |
name | string | ||
captchaText | string | ||
captchaProbe | string | ||
turnstileToken | string | ||
termsAccepted | boolean |
Responses
| Status | Description |
|---|---|
| 201 | OK |
| 400 | Invalid request body or query - every violation found (missing/invalid/unexpected fields) is reported in one response, semicolon-separated, not just the first one hit. |
| 403 | Missing or invalid API key |
| 405 | The operation is blocked by a business rule (e.g. the resource is still in use) |
Response body
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | ||
redirectTo | string |