requestPhotoDeletion
Guest-callable soft-delete for a single photo, gated on the uploader's session ID.
POST /requestPhotoDeletion Soft-deletes a photo (status="deleted") on behalf of the guest who uploaded it. No Firebase Auth identity required — the integrity check is a stable sessionId the browser generated at upload time. Rate-limited to 30 requests per IP per hour. Cleaned up via cleanup-deleted.mjs after the 90-day retention window.
AUTH NOTE
No authentication. Integrity is gated on a domain-specific check (uploader sessionId, gallery password, etc.). Rate-limited per IP.
Request
| Field | Type | Required | Description |
|---|---|---|---|
eventId | string | yes | Your Fotowall event ID. No slashes, periods, or whitespace. |
photoId | string | yes | The photo doc ID inside events/{eventId}/photos. |
sessionId | string | yes | The uploader's session ID (min 8, max 128 chars). Must match the value stamped on the photo doc if present. |
EXAMPLE BODY
{
"eventId": "spring-gala-2026",
"photoId": "ph_8a92",
"sessionId": "sess_4f7d2b8c9e1a3f6b"
} Response
| Field | Type | Always present | Description |
|---|---|---|---|
ok | boolean | yes | Always true on success. If the photo was already deleted, returns ok=true (idempotent). |
EXAMPLE BODY
{
"ok": true
} curl
curl -X POST https://us-central1-freedomgrc-photowall.cloudfunctions.net/requestPhotoDeletion \
-H "Content-Type: application/json" \
-d '{
"data": {
"eventId": "spring-gala-2026",
"photoId": "ph_8a92",
"sessionId": "sess_4f7d2b8c9e1a3f6b"
}
}' JavaScript
We don't ship a first-party JS SDK yet (it's on the roadmap).
For callable endpoints, the Firebase Functions SDK is the recommended
path — it handles ID-token attachment and payload framing.
Plain fetch works too.
// Callable Cloud Functions wrap their payload under { data: ... }
// when invoked over HTTPS directly.
const response = await fetch(
'https://us-central1-freedomgrc-photowall.cloudfunctions.net/requestPhotoDeletion',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
data: {
eventId: 'spring-gala-2026',
photoId: 'ph_8a92',
sessionId: 'sess_4f7d2b8c9e1a3f6b',
},
}),
},
);
const { result } = await response.json();
// result === { ok: true } Error cases
| Code | When |
|---|---|
invalid-argument | eventId, photoId, or sessionId failed validation (length, regex, presence). |
not-found | No photo at events/{eventId}/photos/{photoId}. |
permission-denied | sessionId did not match the uploaderSessionId stamped on the photo. |
resource-exhausted | IP exceeded 30 calls/hour rate limit. |
internal | Firestore read/write failed. Sentry-reported, safe to retry. |
Need a different shape?
The API surface is small. Tell us what you need and we'll work backward from your integration.