Home
Back in Stock

Signups

The waitlist resource: CRUD, notify-now, bulk operations, variant transfers, and the read-only notification send log.

A signup is one customer waiting on one variant over one channel. Internally these are Intent rows; v1 exposed them as "intents".

Path prefix: /back_in_stock/signups

The status field

Every signup carries a compiled lifecycle status, derived from its timestamps:

StatusMeaning
pendingWaiting — no notification sent yet
notifiedThe back-in-stock alert was sent
unsubscribedThe contact opted out
blockedA send was attempted but stopped (e.g. plan limits)

Precedence when several timestamps are set: unsubscribed wins (the contact opted out), then notified, then blocked; a row with none of the three is pending.

Note

The status filter on list accepts pending, notified, and unsubscribed only — blocked appears in response payloads but is not a filterable value. To find blocked sends, filter the notification log with status=blocked.

List signups

GET /back_in_stock/signups
ParamTypeNotes
channelemail / sms / push
statuspending / notified / unsubscribed
variant_idintegerShopify variant id
product_idintegerShopify product id
emailstringPartial match on the signup's or its customer's email
phonestringPartial match on the signup's or its customer's phone
from, toISO 8601Window on created_at
page, per_pageintegerper_page default 50, max 200

Aliases: "waitlist", "show the waitlist", "notify me list", "who's waiting", "customers waiting for restock"

Response: { "signups": [...], "meta": { "total_count", "page", "per_page", "total_pages" } }.

Read a signup

GET /back_in_stock/signups/:id
{
  "id": "uuid",
  "status": "pending",
  "channel": "email",
  "contact": "jane@example.com",
  "quantity": 1,
  "variant": { "shopify_variant_id": 123, "shopify_product_id": 456, "title": "Small / Blue" },
  "customer": { "id": "uuid", "email": "jane@example.com", "name": "Jane" },
  "optin": { "required": false, "confirmed": null },
  "notifications_sent": 0,
  "last_notified_at": null,
  "created_at": "2026-06-01T12:00:00Z"
}

optin.confirmed is only meaningful when the shop requires double opt-in (see Compliance settings); it is null otherwise.

Create a signup

POST /back_in_stock/signups

Admin-side waitlist creation — the storefront widget keeps its own path. Finds or creates the customer, then creates the signup.

Body fieldRequiredNotes
channelyesemail or sms
shopify_variant_idyes
emailfor the email channel
phonefor the sms channel
shopify_product_idnoResolved from the variant when omitted
quantitynointeger, default 1
namenoCustomer name

Returns: 201 Created with the full signup representation.

Notes: returns 409 Conflict when a pending signup already exists for the same contact + variant + channel — pending signups are unique per contact/variant/channel.

Delete a signup

DELETE /back_in_stock/signups/:id

Aliases: "remove from waitlist", "cancel restock alert", "take customer off the notify me list" Notes: pending signups only — deleting an already-notified signup returns 409 Conflict (history is immutable).

Returns: { "deleted": true, "signup_id": "..." }.

Notify now

POST /back_in_stock/signups/:id/notify

Sends the back-in-stock notification for one signup immediately, regardless of stock state. Delivery runs through the normal notification pipeline.

Body fieldTypeDefaultNotes
allow_resendbooleanfalseRequired to re-notify an already-notified signup

Aliases: "send the restock email", "notify this customer", "resend restock notification" Notes: returns 409 Conflict when the signup was already notified and allow_resend is not set.

Returns: 202 Accepted with { "signup_id": "...", "queued": true }.

Bulk notify

POST /back_in_stock/signups/bulk_notify
Body fieldRequiredNotes
signup_idsyesArray of signup ids, max 1000
allow_resendnoSame gate as single notify

Aliases: "notify the waitlist", "notify everyone waiting", "send restock emails to the whole waitlist"

Responds 200 OK when every send queues, or 207 Multi-Status on partial failure — the body is the same shape either way, so always check failed:

{
  "success": ["id-1", "id-2"],
  "failed": [
    { "signup_id": "id-3", "error": "Signup was already notified. Pass allow_resend to send again." }
  ]
}

Already-notified signups land in failed unless allow_resend is set. A 207 is not an error envelope — the successes in success really did queue.

Bulk delete

POST /back_in_stock/signups/bulk_delete
Body fieldRequiredNotes
signup_idsyesArray of signup ids, max 1000

Aliases: "clear the waitlist", "purge pending restock signups" Notes: pending-only, all-or-nothing — if any id in the batch was already notified, the whole request fails with 422 listing the offending ids, and nothing is deleted.

Returns: { "deleted_count": N }.

Transfer

POST /back_in_stock/signups/transfer

Moves signups from one variant to another — for variant merges or replacements.

Body fieldRequiredNotes
from_shopify_variant_idyesMust differ from the target
to_shopify_variant_idyes
to_shopify_product_idyes
from_shopify_product_idnoResolved from the source variant when omitted
scopenopending (default) / notified / all — which signups move

Aliases: "move the waitlist", "merge waitlists", "shift restock signups to a new variant" Notes: signups that would duplicate a pending signup on the target variant are dropped rather than moved.

Returns: 202 Accepted with { "success": true, "scope": "pending", "from_shopify_variant_id": ..., "to_shopify_variant_id": ... }.

Notifications (the send log)

A separate, read-only resource: one entry per delivery attempt, including sends blocked by plan limits. Use it to answer "who actually got notified, and what didn't go out".

List notifications

GET /back_in_stock/notifications
ParamTypeNotes
channelemail / sms / push
statussent / blocked
variant_idintegerShopify variant id
product_idintegerShopify product id
from, toISO 8601
page, per_pageintegerper_page default 50, max 200

Aliases: "back in stock send log", "who got notified", "notification history" Notes: status=blocked surfaces sends stopped by plan limits (with blocked_reason).

Response: { "notifications": [...], "meta": {...} }.

Read a notification

GET /back_in_stock/notifications/:id
{
  "id": "uuid",
  "status": "sent",
  "blocked_reason": null,
  "channel": "email",
  "contact": "jane@example.com",
  "shopify_variant_id": 123,
  "shopify_product_id": 456,
  "signup_id": "uuid",
  "sent_at": "2026-06-01T12:00:00Z"
}

signup_id links back to the signup the notification was sent for. For aggregate send counts over time, use the notifications report instead.