---
title: "Report a danger spot"
description: "Adds a new danger spot. The reporter's own report counts as their first\n\"still dangerous\" vote, so a new spot starts with `confirmations: 1` and\n`status: unverified`.\n\nWhat happens next depends on the site's moderation setting:\n\n- **Instant publishing (default):** the spot is live immediately and `pending` is `false`.\n- **Held for review:** the spot waits for a moderator and `pending` is `true`. It won't\n  appear in `GET /api/spots` until it's approved.\n\nRate limits: **5 reports per hour** per visitor, and **30 per hour** per network (IP\naddress), since many phones share a carrier IP.\n"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.deathspot.org/llms.txt
> Use this file to discover all available pages before exploring further.

Path: Deathspot UG API › Spots

`POST /api/spots`

Adds a new danger spot. The reporter's own report counts as their first
"still dangerous" vote, so a new spot starts with `confirmations: 1` and
`status: unverified`.

What happens next depends on the site's moderation setting:

- **Instant publishing (default):** the spot is live immediately and `pending` is `false`.
- **Held for review:** the spot waits for a moderator and `pending` is `true`. It won't
  appear in `GET /api/spots` until it's approved.

Rate limits: **5 reports per hour** per visitor, and **30 per hour** per network (IP
address), since many phones share a carrier IP.

## Request body

- `reportSpot.title` (string, required) — Short headline. Phone numbers are replaced with `[removed]`.
  - minLength 3; maxLength 80
- `reportSpot.lat` (number, required)
  - format `double`; min -1.6; max 4.3
- `reportSpot.lng` (number, required)
  - format `double`; min 29.5; max 35.1
- `reportSpot.category` (string, required) — What happens at the spot: `murder` (killing), `mob_action`, `boda_gang`, `robbery` (robbery or snatching), `stabbing` (stabbing or hacking), `kidnapping`, `other`.
  - one of `"murder"`, `"mob_action"`, `"boda_gang"`, `"robbery"`, `"stabbing"`, `"kidnapping"`, `"other"`
- `reportSpot.severity` (integer, required)
  - min 1; max 5
- `reportSpot.time_of_day` (string, required) — When the spot is dangerous.
  - one of `"day"`, `"night"`, `"any"`
- `reportSpot.description` (string, optional) — What happened and when it's dangerous. Describe the place, never a person.
  - maxLength 600; default `""`
- `reportSpot.area` (string, optional)
  - maxLength 80; default `""`
- `reportSpot.incident_date` (string | null, optional)
  - format `date`
- `reportSpot.source_url` (string | null, optional) — An `http` or `https` link. Send `""` or `null` for none.
  - format `uri`; maxLength 300

## Example request

```json
{
  "title": "Boda gang attacks near the junction",
  "description": "Riders snatch phones and bags after 9pm. Walk in groups or take another route.",
  "lat": 0.34918,
  "lng": 32.57195,
  "area": "Kalerwe market",
  "category": "boda_gang",
  "severity": 4,
  "time_of_day": "night",
  "incident_date": "2026-09-20",
  "source_url": "https://www.monitor.co.ug/"
}
```

## Code samples

### cURL

```curl
curl --request POST \
  --url https://deathspot.org/api/spots \
  --header 'Content-Type: application/json' \
  --data '
{
  "title": "Boda gang attacks near the junction",
  "description": "Riders snatch phones and bags after 9pm. Walk in groups or take another route.",
  "lat": 0.34918,
  "lng": 32.57195,
  "area": "Kalerwe market",
  "category": "boda_gang",
  "severity": 4,
  "time_of_day": "night",
  "incident_date": "2026-09-20",
  "source_url": "https://www.monitor.co.ug/"
}
'
```

### TypeScript

```typescript
const url = 'https://deathspot.org/api/spots';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    title: 'Boda gang attacks near the junction',
    description: 'Riders snatch phones and bags after 9pm. Walk in groups or take another route.',
    lat: 0.34918,
    lng: 32.57195,
    area: 'Kalerwe market',
    category: 'boda_gang',
    severity: 4,
    time_of_day: 'night',
    incident_date: '2026-09-20',
    source_url: 'https://www.monitor.co.ug/'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error(err));
```

### Python

```python
import requests

url = "https://deathspot.org/api/spots"

payload = {
    "title": "Boda gang attacks near the junction",
    "description": "Riders snatch phones and bags after 9pm. Walk in groups or take another route.",
    "lat": 0.34918,
    "lng": 32.57195,
    "area": "Kalerwe market",
    "category": "boda_gang",
    "severity": 4,
    "time_of_day": "night",
    "incident_date": "2026-09-20",
    "source_url": "https://www.monitor.co.ug/"
}
headers = {"Content-Type": "application/json"}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
```

## Responses

### 201

The spot was saved.

#### Example

```json
{
  "pending": false,
  "spot": {
    "id": 42,
    "title": "Boda gang attacks near the junction",
    "description": "Riders snatch phones and bags after 9pm. Walk in groups or take another route.",
    "lat": 0.34918,
    "lng": 32.57195,
    "area": "Kalerwe market",
    "category": "boda_gang",
    "severity": 4,
    "time_of_day": "night",
    "incident_date": "2026-09-20",
    "source_url": "https://www.monitor.co.ug/",
    "created_at": "2026-09-24T10:02:31.551Z",
    "last_confirmed_at": "2026-09-24T10:02:31.551Z",
    "confirmations": 1,
    "denials": 0,
    "status": "unverified",
    "moderator_verified": false,
    "seeded": false
  }
}
```

- `reportSpot.response.201.spot` (object, required) — A reported danger spot on the public map.
  - `reportSpot.response.201.spot.id` (integer, required)
    - example `1`
  - `reportSpot.response.201.spot.title` (string, required)
    - maxLength 80; example `"Mukwano Road (near CID HQ)"`
  - `reportSpot.response.201.spot.description` (string, required) — What people should know about the place. It may be empty.
    - maxLength 600
  - `reportSpot.response.201.spot.lat` (number, required)
    - format `double`; min -1.6; max 4.3; example `0.30827`
  - `reportSpot.response.201.spot.lng` (number, required)
    - format `double`; min 29.5; max 35.1; example `32.58721`
  - `reportSpot.response.201.spot.area` (string, required) — Neighbourhood, division or landmark. It may be empty.
    - maxLength 80; example `"Kibuli, Makindye"`
  - `reportSpot.response.201.spot.category` (string, required) — What happens at the spot: `murder` (killing), `mob_action`, `boda_gang`, `robbery` (robbery or snatching), `stabbing` (stabbing or hacking), `kidnapping`, `other`.
    - one of `"murder"`, `"mob_action"`, `"boda_gang"`, `"robbery"`, `"stabbing"`, `"kidnapping"`, `"other"`
  - `reportSpot.response.201.spot.severity` (integer, required) — 1 = feels unsafe, 2 = harassment or threats, 3 = robbery or snatching, 4 = violent attack, 5 = someone was killed.
    - min 1; max 5; example `5`
  - `reportSpot.response.201.spot.time_of_day` (string, required) — When the spot is dangerous.
    - one of `"day"`, `"night"`, `"any"`
  - `reportSpot.response.201.spot.incident_date` (string | null, required)
    - format `date`; example `"2026-09-23"`
  - `reportSpot.response.201.spot.source_url` (string | null, required) — A news, police or court source, if the reporter gave one.
    - format `uri`
  - `reportSpot.response.201.spot.created_at` (string, required)
    - format `date-time`
  - `reportSpot.response.201.spot.last_confirmed_at` (string | null, required) — When someone last voted "still dangerous".
    - format `date-time`
  - `reportSpot.response.201.spot.confirmations` (integer, required) — Number of "still dangerous" votes.
    - min 0
  - `reportSpot.response.201.spot.denials` (integer, required) — Number of "not anymore" votes.
    - min 0
  - `reportSpot.response.201.spot.status` (string, required) — The community's verdict from votes. `confirmed` needs at least 3 more confirmations than denials, and `disputed` means denials outnumber confirmations by more than 2.
    - one of `"unverified"`, `"confirmed"`, `"disputed"`
  - `reportSpot.response.201.spot.moderator_verified` (boolean, required) — `true` when a moderator has checked the spot against a reliable source. Shown as "Verified by moderators".
  - `reportSpot.response.201.spot.seeded` (boolean, required) — `true` for spots loaded from the project's sourced seed data rather than reported through the app.
- `reportSpot.response.201.pending` (boolean, required) — `true` when the spot is held for moderator review and not yet on the public map.

### 400

The report failed validation, for example because the location is outside Uganda or the title is too short.

#### Example

```json
{
  "error": "Location must be inside Uganda",
  "issues": [
    {
      "code": "custom",
      "path": [
        "lat"
      ],
      "message": "Location must be inside Uganda"
    }
  ]
}
```

- `reportSpot.response.400.error` (string, required) — A human-readable message you can show to users.
- `reportSpot.response.400.issues` (array<object>, optional) — Every validation problem, in zod's issue format.
  - `reportSpot.response.400.issues.code` (string, optional)
  - `reportSpot.response.400.issues.path` (array<string | integer>, optional)
  - `reportSpot.response.400.issues.message` (string, optional)

### 429

The caller exceeded a rate limit. Wait `Retry-After` seconds before retrying.

#### Example

```json
{
  "error": "You have reported a lot of spots recently. Please try again in an hour."
}
```

- `reportSpot.response.429.error` (string, required) — A human-readable message you can show to users.

### 500

Unexpected server error, usually because the database is unreachable.

#### Example

```text
string
```


Source: https://docs.deathspot.org/api/Spots/reportSpot/index.md
