BIO.RE
Creator

Unsubscribe

Public soft-delete endpoint. Sets unsubscribedAt = now() — the row stays for audit but is excluded from active subscriber lists and future newsletter dispatches.

GET /api/v1/creators/unsubscribe — 🌐 Public · Rate limit: 10 req / minute

Soft-unsubscribes a fan from a bio page mailing list. Soft-delete: sets unsubscribedAt = now() rather than removing the row, so the audit trail (when did this person sign up, when did they leave) stays intact. The row is excluded from GET /creators/subscribers (which filters unsubscribedAt IS NULL) and from future newsletter dispatches.

The unsubscribe link in newsletter emails is built with the subscriber's id (not email) as the query param — anyone with the link can unsubscribe that subscriber. This is standard mailing-list UX and intentional.

Request

Query parameters

ParamTypeRequiredNotes
idstringThe BioEmailSubscriber.id from the unsubscribe link in the newsletter email

No body, no headers required.

Response

200 OKSuccessOnlyResponseDto

{
  "success": true
}
FieldTypeNotes
successbooleanAlways true on 200

Errors

HTTPcode / i18nKeyReason
404creator.subscribe.not_foundid missing or no BioEmailSubscriber row matches
429(throttle)Rate limit exceeded (10 req/min)

Side effects

  1. Reject empty idnot_found.
  2. bioEmailSubscriber.findUnique({ where: { id: subscriberId } }). Missing → not_found.
  3. bioEmailSubscriber.update({ where: { id }, data: { unsubscribedAt: new Date() } }).
  4. Return { success: true }. The row is NOT deleted; it's just timestamped as unsubscribed.

Code samples

curl 'https://api.bio.re/api/v1/creators/unsubscribe?id=s1u2b3c4-d5e6-7890-abcd-ef1234567890'
async function unsubscribe(subscriberId: string): Promise<void> {
  const url = new URL('https://api.bio.re/api/v1/creators/unsubscribe');
  url.searchParams.set('id', subscriberId);
  const res = await fetch(url);
  const json = await res.json();
  if (!res.ok || !json.success) {
    throw Object.assign(new Error(json?.error?.message ?? 'Unsubscribe failed'), {
      code: json?.error?.code,
    });
  }
}
import { useMutation } from '@tanstack/react-query';

export function useUnsubscribe() {
  return useMutation({
    mutationFn: async (subscriberId: string) => {
      const url = new URL('/api/v1/creators/unsubscribe', window.location.origin);
      url.searchParams.set('id', subscriberId);
      const res = await fetch(url);
      const json = await res.json();
      if (!res.ok || !json.success) {
        throw Object.assign(new Error(json?.error?.message ?? 'Unsubscribe failed'), {
          code: json?.error?.code,
          i18nKey: json?.error?.i18nKey,
        });
      }
    },
  });
}

Try it

GET
/api/v1/creators/unsubscribe
AuthorizationBearer <token>

In: header

Query Parameters

id*string

Response Body

application/json

application/json

curl -X GET "https://loading/api/v1/creators/unsubscribe?id=string"
{
  "success": true
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Source

SourcePathLines
Controllerapps/api-core/src/modules/creator/creator.controller.ts329–337 (unsubscribe)
DTO (response)apps/api-core/src/common/dto/common-response.dto.tsSuccessOnlyResponseDto
Serviceapps/api-core/src/modules/creator/creator.service.ts714–729 (unsubscribe)
Prisma modelpackages/prisma/prisma/schema.prismaBioEmailSubscriber.unsubscribedAt

On this page