Delete Bio Link
Hard-delete a single bio link by id. Ownership-checked. The owning creator's public bio cache is invalidated; cache lookup failures don't block the delete.
DELETE /api/v1/creators/links/:linkId — 🔑 Bearer · Rate limit: 30 req / hour
Hard-deletes a BioLink row. Ownership is checked via the link's bio page → creator → user chain. The owning creatorId is fetched before the delete so the public bio cache can be invalidated even after the row is gone — failures of that pre-lookup are swallowed and the delete proceeds.
Hard delete, not soft. Use PATCH /creators/links/:linkId with active: false if you want a temporarily-hidden link the creator can re-enable. There's no recycle bin or undo flow on this endpoint.
Request
Path parameters
| Param | Type | Validation | Notes |
|---|---|---|---|
linkId | string (UUID) | ParseUUIDPipe | Must belong to a bio page owned by the bearer's user |
No body.
| 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. The link no longer exists; sortOrder of remaining links is not automatically compacted (call POST /creators/:creatorId/links/reorder if your UI requires gap-free ordering). |
Errors
| HTTP | code / i18nKey | Reason |
|---|---|---|
400 | (validation) | linkId not a valid UUID |
401 | (guard) | Missing / invalid bearer token |
403 | creator.links.not_owner | Link's bio page belongs to a different user |
404 | creator.links.not_found | BioLink row missing |
429 | (throttle) | Rate limit exceeded (30 req/hour) |
Side effects
- Ownership check —
verifyLinkOwnership(linkId, userId)→ 403 on mismatch. - Pre-fetch creatorId — read the link's
bioPage.creatorIdwhile the row still exists (failures are caught and ignored — the delete still proceeds). prisma.bioLink.delete({ where: { id: linkId } }).- If the pre-fetch succeeded:
invalidateBioCache(creatorId). Otherwise the cache will expire naturally.
Code samples
curl -X DELETE https://api.bio.re/api/v1/creators/links/l1a2b3c4-d5e6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer $ACCESS_TOKEN"async function deleteBioLink(accessToken: string, linkId: string): Promise<void> {
const res = await fetch(`https://api.bio.re/api/v1/creators/links/${linkId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${accessToken}` },
});
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Delete link failed'), {
code: json?.error?.code,
});
}
}import { useMutation, useQueryClient } from '@tanstack/react-query';
export function useDeleteBioLink(creatorId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: async (linkId: string) => {
const res = await fetch(`/api/v1/creators/links/${linkId}`, { method: 'DELETE' });
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Delete link failed'), {
code: json?.error?.code,
i18nKey: json?.error?.i18nKey,
});
}
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['creators', creatorId, 'bio'] });
},
});
}Try it
Authorization
bearer In: header
Path Parameters
Response Body
application/json
application/json
application/json
application/json
curl -X DELETE "https://loading/api/v1/creators/links/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"
}
}{
"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 | 176–187 (deleteLink), 107–114 (verifyLinkOwnership) |
| DTO (response) | apps/api-core/src/common/dto/common-response.dto.ts | SuccessOnlyResponseDto |
| Service | apps/api-core/src/modules/creator/creator.service.ts | 444–462 (deleteLink) |
| Prisma models | packages/prisma/prisma/schema.prisma | BioLink, BioPage (relation chain for ownership) |
Update Bio Link
Sparse update of a bio link. URL revalidation re-runs embed auto-detection. Title HTML-stripped + moderation-checked. Schedule end must follow start. Cache invalidation is best-effort.
Reorder Bio Links
Atomic reordering of bio page links. Submit the full ordered array; sortOrder is set to the array index. Server verifies every linkId belongs to the creator before writing.