Set Vacation Mode
Toggle vacation mode with optional start/end window. Status flips ACTIVE↔VACATION only — SUSPENDED/BANNED/DEACTIVATED accounts are protected from this transition.
PATCH /api/v1/creators/:creatorId/vacation — 🔑 Bearer · Rate limit: 30 req / hour
Toggles CreatorProfile.vacationMode and updates the optional vacationStart / vacationEnd window. Atomically syncs the canonical creatorStatus enum: ACTIVE → VACATION when enabling, VACATION → ACTIVE when disabling. SUSPENDED / BANNED / DEACTIVATED accounts are protected — the status enum is left untouched (only the legacy vacationMode boolean updates).
Status protection is a safety guard, not a feature gap. A vacation toggle can never accidentally un-suspend or un-ban an account. If you're seeing vacationMode: true while creatorStatus !== 'VACATION', the account is in a moderated state — direct the user to support, not to a vacation toggle.
Public-render impact: while vacationMode: true, the public bio page (GET /bio/:username) returns dmActive: false (computed as dmActive && !vacationMode) regardless of the raw dmActive flag. The bio still renders — only the DM accept-state flips off.
Request
Path parameters
| Param | Type | Validation | Notes |
|---|---|---|---|
creatorId | string (UUID) | ParseUUIDPipe | Must match the bearer's CreatorProfile.id (otherwise 403) |
Body — SetVacationDto
| Field | Type | Required | Validation | Notes |
|---|---|---|---|---|
enabled | boolean | ✓ | IsBoolean() | true to enter vacation mode, false to exit |
startDate | string (ISO 8601) | optional | IsDateString() | Defaults to now() when enabled: true and not supplied |
endDate | string (ISO 8601) | optional | IsDateString() | Open-ended (null) when not supplied. Must be after startDate (when both present). |
| Header | Required | Notes |
|---|---|---|
Authorization: Bearer <accessToken> | ✓ | JWT from POST /auth/login |
Response
200 OK — SuccessOnlyResponseDto
{
"success": true
}| Field | Type | Notes |
|---|---|---|
success | boolean | Always true on 200. Re-fetch via GET /creators/:creatorId/vacation for the post-write state. |
Errors
| HTTP | code / i18nKey | Reason |
|---|---|---|
400 | creator.vacation.invalid_date_range | enabled: true AND both dates supplied AND endDate <= startDate |
400 | (DTO validation) | enabled missing; date strings malformed |
401 | (guard) | Missing / invalid bearer token |
403 | (verifyCreatorOwnership) | creatorId does not belong to the bearer's user |
429 | (throttle) | Rate limit exceeded (30 req/hour) |
Side effects
- Ownership check —
verifyCreatorOwnership(creatorId, userId)→ 403 on mismatch. - Date range validation — when
enabled: trueAND both dates present ANDendDate <= startDate→ throwinvalid_date_range. - Read current
creatorStatus. Compute the safe transition:enabled: true AND status === ACTIVE→ flip toVACATION.enabled: false AND status === VACATION→ flip toACTIVE.- Any other status (
SUSPENDED/BANNED/DEACTIVATED) → status stays unchanged.
- Single atomic update of
CreatorProfile:vacationMode = enabled.vacationStart = enabled ? (startDate ?? now()) : null.vacationEnd = enabled ? (endDate ?? null) : null.creatorStatuswritten only for the safe ACTIVE↔VACATION transitions above.
- Audit log:
[vacation] Enabled/Disabled for creator {id} (status→VACATION | status unchanged — protected).
Code samples
curl -X PATCH https://api.bio.re/api/v1/creators/c1a2b3c4-d5e6-7890-abcd-ef1234567890/vacation \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"startDate": "2026-07-01T00:00:00Z",
"endDate": "2026-07-15T00:00:00Z"
}'type SetVacationInput = {
enabled: boolean;
startDate?: string;
endDate?: string;
};
async function setVacationMode(accessToken: string, creatorId: string, input: SetVacationInput): Promise<void> {
const res = await fetch(`https://api.bio.re/api/v1/creators/${creatorId}/vacation`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Vacation update failed'), {
code: json?.error?.code,
});
}
}import { useMutation, useQueryClient } from '@tanstack/react-query';
export function useSetVacationMode(creatorId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: async (input: SetVacationInput) => {
const res = await fetch(`/api/v1/creators/${creatorId}/vacation`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(input),
});
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Vacation update failed'), {
code: json?.error?.code,
i18nKey: json?.error?.i18nKey,
});
}
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['creators', creatorId, 'vacation'] });
// creatorStatus may have flipped — refresh profile views
qc.invalidateQueries({ queryKey: ['creators', 'profile'] });
},
});
}Try it
Authorization
bearer In: header
Path Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
curl -X PATCH "https://loading/api/v1/creators/string/vacation" \ -H "Content-Type: application/json" \ -d '{ "enabled": true }'{
"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"
}
}{
"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"
}
}{
"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
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/creator/creator.controller.ts | 237–252 (setVacation) |
| DTO (request) | apps/api-core/src/modules/creator/dto/creator-social.dto.ts | 40–49 (SetVacationDto) |
| DTO (response) | apps/api-core/src/common/dto/common-response.dto.ts | SuccessOnlyResponseDto |
| Service | apps/api-core/src/modules/creator/creator.service.ts | 582–613 (setVacationMode — handles status protection) |
| Prisma models | packages/prisma/prisma/schema.prisma | CreatorProfile.vacationMode, CreatorProfile.vacationStart, CreatorProfile.vacationEnd, CreatorProfile.creatorStatus (enum CreatorStatus) |