# Agrawal Properties — Mobile API Reference

Base URL: `/api`  
Authentication: Laravel Sanctum — include `Authorization: Bearer <token>` on all authenticated endpoints.  
All responses follow the envelope format:

```json
{ "status": true|false, "message": "...", "result": { ... } }
```

---

## Authentication

### POST /api/auth/login
Public. Exchange credentials for a Sanctum token.

**Request body**
```json
{ "email": "user@example.com", "password": "secret" }
```

**Success 200**
```json
{
  "status": true,
  "message": "Login successful.",
  "result": {
    "token": "<sanctum-token>",
    "role": "admin|staff",
    "user": { "id": 1, "name": "...", "email": "...", "mobile": "..." }
  }
}
```

**Errors:** `401` invalid credentials / inactive account.

---

### POST /api/auth/logout _(auth)_
Revokes the current token.

### GET /api/auth/me _(auth)_
Returns the authenticated user's profile.

---

## Device Registration

### POST /api/auth/device _(auth)_
Register a device for push notifications.

**Request body**
```json
{ "player_id": "...", "device_type": "ios|android|web" }
```

### DELETE /api/auth/device _(auth)_
Unregister the current device token.

---

## Clients

### GET /api/clients _(auth)_
Paginated list. Non-admins see only their assigned clients.

**Query params:** `?search=<name|mobile>`

### POST /api/clients _(auth)_
Create a client. Non-admins are automatically set as assigned owner.

### GET /api/clients/{id} _(auth)_

### PUT /api/clients/{id} _(auth)_

### GET /api/clients/{client}/requirements _(auth)_
### POST /api/clients/{client}/requirements _(auth)_
### PUT /api/requirements/{requirement}/close _(auth)_

---

## Owners

### GET /api/owners _(auth)_
**Query params:** `?search=<name|mobile>`

### GET /api/owners/{id} _(auth)_

---

## Property Types

### GET /api/property-types _(auth)_
Returns active property types ordered by `sort_order`. Used by mobile apps to build dynamic property creation forms.

**Response**
```json
{
  "status": true,
  "message": "Property types fetched successfully.",
  "result": [
    { "id": 1, "name": "Flat / Apartment", "slug": "flat", "sort_order": 1 },
    { "id": 2, "name": "Plot / Land",      "slug": "plot", "sort_order": 2 }
  ]
}
```

---

## Properties

### GET /api/properties _(auth)_
Non-admins see only published properties.

**Query params**
| Param    | Description                        |
|----------|------------------------------------|
| `search` | Search by title or location        |
| `type`   | Property type slug (e.g. `flat`)   |

### GET /api/properties/{id} _(auth)_
Full property detail including images, documents, price history.

### GET /api/properties/{property}/images _(auth)_
### POST /api/properties/{property}/images _(auth)_
Upload a property image (multipart).

### GET /api/properties/{property}/documents _(auth)_
Lists documents. Each item includes a `download_url`.

### GET /api/property-documents/{document}/download _(auth)_
Stream/download a property-specific document file.

---

## Centralised Documents

Documents for any entity (property, owner, client, agreement) are accessible through these endpoints.

### GET /api/entities/{type}/{id}/documents _(auth)_
`type` must be one of: `property`, `owner`, `client`, `agreement`.  
Access is role-restricted per entity type (staff cannot access `agreement` documents).

**Response item**
```json
{
  "id": 9,
  "document_type": "Sale Deed",
  "original_filename": "deed.pdf",
  "mime_type": "application/pdf",
  "file_size_kb": 204,
  "file_size": "204 KB",
  "uploaded_by": "Admin User",
  "uploaded_at": "2026-05-01T10:00:00Z",
  "download_url": "/api/documents/9/download"
}
```

### GET /api/documents/{id}/download _(auth)_
Download a document by its ID. Streams the file with the original filename.

**Errors**
| Status | Reason |
|--------|--------|
| `404`  | Document not found |
| `403`  | Insufficient permissions for this entity type |

---

## Leads

### GET /api/leads _(auth)_
Paginated active leads. Non-admins see only their assigned leads.

**Query params**
| Param    | Type            | Description                                                  |
|----------|-----------------|--------------------------------------------------------------|
| `page`   | integer         | Page number (default: 1)                                     |
| `stage`  | integer\|string | Filter by stage ID (integer) or partial stage name (string)  |
| `search` | string          | Search client name, mobile, or email                         |

**Response**
```json
{
  "status": true,
  "message": "Leads fetched successfully.",
  "result": {
    "data": [ { "id": 1, "client_name": "...", "current_stage": { "id": 2, "name": "Negotiation", "color": "#f59e0b" }, "days_in_stage": 3, ... } ],
    "pagination": { "total": 42, "per_page": 20, "current_page": 1, "last_page": 3 }
  }
}
```

### GET /api/leads/{id} _(auth)_
Full lead detail: requirement, stage history, shortlisted properties, site visits, activity log, quotes, agreement.

### PUT /api/leads/{id}/stage _(auth)_
**Request body:** `{ "stage_id": 3, "note": "optional reason" }`

---

## Pipeline Stages

### GET /api/stages _(auth)_
Returns all active stages in pipeline order.

---

## Shortlisted Properties

### GET /api/leads/{lead}/shortlisted _(auth)_
### POST /api/leads/{lead}/shortlist _(auth)_
**Body:** `{ "property_id": 5 }`  
**Errors:** `409` if already shortlisted.

### DELETE /api/leads/{lead}/shortlist/{property} _(auth)_
**Body:** `{ "reason": "...", "notes": "..." }`

---

## Site Visits

### GET /api/leads/{lead}/visits _(auth)_
### POST /api/leads/{lead}/visits _(auth)_
**Body:** `{ "property_id": 5, "visit_date": "2026-05-20", "visit_time": "10:30", "accompanying_staff": "...", "notes": "..." }`

---

## Activity Log

### GET /api/leads/{lead}/activity _(auth)_

---

## Notes

### POST /api/leads/{lead}/notes _(auth)_
**Body:** `{ "note": "Up to 2000 characters" }`

---

## Reminders

### GET /api/reminders _(auth)_
Non-admins see only reminders assigned to them.

**Query params**
| Param    | Values                       | Description                                       |
|----------|------------------------------|---------------------------------------------------|
| `filter` | `today`                      | Due today, not done                               |
| `filter` | `upcoming`                   | Due after today, not done                         |
| `filter` | `done`                       | Completed reminders (ordered by `done_at` desc)   |
| _(none)_ | —                            | All pending (overdue + today + upcoming)          |

**Response item**
```json
{
  "id": 3,
  "message": "Follow up on budget confirmation",
  "remind_at": "2026-05-22T09:00:00Z",
  "is_done": false,
  "done_at": null,
  "is_overdue": false,
  "lead_id": 7,
  "client_name": "Ravi Mehta"
}
```

### POST /api/leads/{lead}/reminders _(auth)_
**Body**
```json
{ "message": "...", "remind_at": "2026-05-25", "assigned_to": 4 }
```
`assigned_to` is optional; admins may assign to any staff member.

### PUT /api/reminders/{id}/done _(auth)_
Marks a reminder as completed.

---

## Quotes

### GET /api/leads/{lead}/quotes _(auth)_
### POST /api/leads/{lead}/quotes _(auth)_
**Body:** `{ "property_id": 5, "quoted_price": 4500000, "quote_date": "2026-05-20", "shared_by": "Email", "notes": "..." }`

---

## Agreements

### POST /api/leads/{lead}/agreement _(auth)_
**Body (sale)**
```json
{
  "property_id": 5, "deal_type": "sale",
  "client_name": "...", "owner_name": "...",
  "agreed_price": 4500000, "deal_date": "2026-05-20", "notes": "..."
}
```
**Additional fields for `deal_type: rental`**
```json
{
  "agreement_start_date": "2026-06-01",
  "agreement_end_date": "2027-05-31",
  "monthly_rent": 25000,
  "rent_escalation_clause": "5% per annum",
  "expiry_reminder_days": 30
}
```

---

## Error Reference

| HTTP Status | Meaning                          |
|-------------|----------------------------------|
| `200`       | Success                          |
| `201`       | Created                          |
| `400`       | Bad request / general error      |
| `401`       | Unauthenticated                  |
| `403`       | Forbidden (role/ownership check) |
| `404`       | Resource not found               |
| `409`       | Conflict (e.g. duplicate)        |
| `422`       | Validation failed                |
