Business Admin · API Reference
✓ Testedbusiness_id scoped
Base URL/api/admin/ for all endpoints
Scope — all queries filtered by authenticated user's business_id
AuthAuthorization: Bearer {sanctum_token} · user_type must be admin or staff
Envelope{ "success": true, "msg": "...", "data": [...], "pagination": {...} }
πŸ“Š

Dashboard

GET/api/admin/dashboardTested

Business-scoped KPI summary. Returns live counts of projects, proposals, open vouchers, and upcoming calendar events.

Permission required
dashboard.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Dashboard",
  "data": {
    "project_count": 12,
    "active_project_count": 7,
    "proposal_count": 18,
    "open_voucher_count": 4,
    "upcoming_event_count": 3,
    "welcome_message": "Business admin dashboard"
  }
}
Errors
401 Unauthenticated403 Forbidden
πŸ—

Projects

GET/api/admin/projectsTested

Paginated list of project. Scoped to authenticated business.

Permission required
projects.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Projects",
  "data": {
    "id": 4,
    "business_id": 1,
    "location_id": 1,
    "client_user_id": 5,
    "name": "Residential Block A β€” Phase 2",
    "description": "Foundation and framing works",
    "status": "active",
    "contract_value": 2500000.0,
    "current_phase_key": "foundation",
    "address": "Plot 12, DHA Phase 8, Karachi"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/projectsTested

Create a new project record. If template_id is provided, the API auto-creates phases using the template's phase_keys and Phase Library default_duration_days values.

Permission required
projects.manage
Request body
JSON
{
  "name": "Residential Block A β€” Phase 2",
  "description": "Foundation and framing works",
  "location_id": 1,
  "client_user_id": 5,
  "status": "active",
  "contract_value": 2500000,
  "start_date": "2026-07-01",
  "expected_end_date": "2026-12-31",
  "current_phase_key": "foundation",
  "address": "Plot 12, DHA Phase 8, Karachi",
  "template_id": 2
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Projects",
  "data": {
    "id": 4,
    "business_id": 1,
    "location_id": 1,
    "client_user_id": 5,
    "name": "Residential Block A β€” Phase 2",
    "description": "Foundation and framing works",
    "status": "active",
    "contract_value": 2500000.0,
    "current_phase_key": "foundation",
    "address": "Plot 12, DHA Phase 8, Karachi"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/projects/{id}Tested

Retrieve one project by ID.

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Projects",
  "data": {
    "id": 4,
    "business_id": 1,
    "location_id": 1,
    "client_user_id": 5,
    "name": "Residential Block A β€” Phase 2",
    "description": "Foundation and framing works",
    "status": "active",
    "contract_value": 2500000.0,
    "current_phase_key": "foundation",
    "address": "Plot 12, DHA Phase 8, Karachi"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/projects/{id}Tested

Update any fields on an existing project. All fields optional.

Permission required
projects.manage
Request body
JSON
{
  "name": "Residential Block A β€” Phase 2",
  "description": "Foundation and framing works",
  "location_id": 1,
  "client_user_id": 5,
  "status": "active",
  "contract_value": 2500000,
  "start_date": "2026-07-01",
  "expected_end_date": "2026-12-31",
  "current_phase_key": "foundation",
  "address": "Plot 12, DHA Phase 8, Karachi"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Projects",
  "data": {
    "id": 4,
    "business_id": 1,
    "location_id": 1,
    "client_user_id": 5,
    "name": "Residential Block A β€” Phase 2",
    "description": "Foundation and framing works",
    "status": "active",
    "contract_value": 2500000.0,
    "current_phase_key": "foundation",
    "address": "Plot 12, DHA Phase 8, Karachi"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/projects/{id}Tested

Permanently delete this project.

Permission required
projects.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ”

Project Detail Sub-routes

All sub-routes require projects.view. Project must belong to admin's business.

GET/api/admin/projects/{id}/phasesTested

All phases for a project ordered by sort_order.

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Phases",
  "data": [
    {
      "id": 1,
      "project_id": 4,
      "phase_key": "foundation",
      "name": "Foundation Works",
      "status": "in_progress",
      "progress_percent": 65,
      "sort_order": 1
    }
  ],
  "pagination": {"current_page":1,"per_page":20,"total":3,"last_page":1}
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/projects/{id}/proposalsTested

All proposals linked to a project.

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposals",
  "data": [
    {
      "id": 2,
      "business_id": 1,
      "project_id": 4,
      "title": "Revised foundation proposal",
      "status": "accepted",
      "quoted_amount": 2500000.0,
      "current_round": 2
    }
  ],
  "pagination": {"current_page":1,"per_page":20,"total":2,"last_page":1}
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/projects/{id}/vouchersTested

All vouchers for a project.

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Vouchers",
  "data": [
    {
      "id": 7,
      "business_id": 1,
      "project_id": 4,
      "subcontractor_id": 2,
      "voucher_no": "VCH-2026-0007",
      "voucher_type": "subcontractor",
      "status": "submitted",
      "amount": 185000.0,
      "week_ending": "2026-06-21"
    }
  ],
  "pagination": {"current_page":1,"per_page":20,"total":4,"last_page":1}
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/projects/{id}/ledgersTested

Ledger entries for a project, ordered by entry_date desc.

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Ledgers",
  "data": [
    {
      "id": 3,
      "business_id": 1,
      "project_id": 4,
      "party_type": "subcontractor",
      "party_id": 2,
      "entry_type": "payment",
      "debit": 0.0,
      "credit": 185000.0,
      "reference": "VCH-2026-0007",
      "description": "Payment for week ending 21 Jun 2026",
      "entry_date": "2026-06-22"
    }
  ],
  "pagination": {"current_page":1,"per_page":20,"total":3,"last_page":1}
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/projects/{id}/revisionsTested

Contract and drawing revisions for a project (not paginated, returns object with two arrays).

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Revisions",
  "data": {
    "contracts": [
      {
        "id": 1,
        "type": "contract",
        "revision_number": 2,
        "status": "signed",
        "contract_value": 2500000.0,
        "file_path": "contracts/proj4-rev2.pdf"
      }
    ],
    "drawings": [
      {
        "id": 1,
        "type": "drawing",
        "drawing_code": "DWG-A-001",
        "revision_number": 3,
        "status": "approved",
        "file_path": "drawings/DWG-A-001-rev3.pdf"
      }
    ]
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/projects/{id}/materialsTested

Material stock entries for a project.

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Materials",
  "data": [
    {
      "id": 1,
      "project_id": 4,
      "material_name": "OPC Cement 50kg",
      "unit": "bags",
      "quantity_on_hand": 240.0,
      "quantity_reserved": 60.0
    }
  ],
  "pagination": {"current_page":1,"per_page":20,"total":5,"last_page":1}
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/projects/{id}/logsTested

Daily progress logs for a project, newest first.

Permission required
projects.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Daily logs",
  "data": [
    {
      "id": 1,
      "business_id": 1,
      "project_id": 4,
      "subcontractor_id": 2,
      "user_id": 3,
      "log_date": "2026-06-22",
      "work_summary": "Completed 3 column foundations; 8 workers on site",
      "workers_count": 8,
      "status": "submitted"
    }
  ],
  "pagination": {"current_page":1,"per_page":20,"total":18,"last_page":1}
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ“„

Proposals

GET/api/admin/proposalsTested

Paginated list of proposals. Scoped to authenticated business. project_name is resolved via the project relation β€” never just project_id.

Permission required
proposals.view
Parameters
ParamDescription
searchOptional. Matches against title OR the linked project's name (case-insensitive substring).
statusOptional. Exact match on one of: draft, scheduled, in_review, revision_requested, accepted, deposit_paid, converted (see GET /api/common/proposal-stages). Unknown value β†’ empty data: [], not an error.
project_idOptional. Restrict to proposals on one project. Must belong to the authenticated business β€” invalid id β†’ empty data: [].
pageOptional. Default 1.
per_pageOptional. Default 20. Pass -1 for unpaginated.
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposals",
  "data": [
    {
      "id": 3,
      "business_id": 1,
      "project_id": 4,
      "project_name": "Block A",
      "title": "Revised foundation proposal round 2",
      "status": "draft",
      "quoted_amount": 2500000.0,
      "current_round": 2
    }
  ],
  "pagination": {"current_page": 1, "per_page": 20, "total": 1, "last_page": 1}
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/proposalsTested

Create a new proposal record.

Permission required
proposals.manage
Request body
FieldDescription
project_idRequired. Integer. Must belong to the authenticated business.
titleRequired. String, max 255.
statusOptional. String, max 32. One of the 7 canonical proposal_stages values; defaults to draft at the DB level if omitted.
quoted_amountOptional. Numeric, β‰₯0.
current_roundOptional. Integer, β‰₯0. Bump manually on each new negotiation round.
JSON
{
  "project_id": 4,
  "title": "Revised foundation proposal round 2",
  "status": "draft",
  "quoted_amount": 2500000,
  "current_round": 2
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Created",
  "data": {
    "id": 3,
    "business_id": 1,
    "project_id": 4,
    "project_name": "Block A",
    "title": "Revised foundation proposal round 2",
    "status": "draft",
    "quoted_amount": 2500000.0,
    "current_round": 2
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/proposals/{id}Tested

Retrieve one proposal by ID.

Permission required
proposals.view
Path parameters
ParamDescription
idRequired. Proposal ID. Must belong to the authenticated business β€” otherwise 404.
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposals",
  "data": {
    "id": 3,
    "business_id": 1,
    "project_id": 4,
    "project_name": "Block A",
    "title": "Revised foundation proposal round 2",
    "status": "draft",
    "quoted_amount": 2500000.0,
    "current_round": 2
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/proposals/{id}Tested

Update any fields on an existing proposal. All fields optional.

Permission required
proposals.manage
Request body
FieldDescription
project_idOptional. Integer. Must belong to the authenticated business.
titleOptional. String, max 255.
statusOptional. String, max 32. One of the 7 canonical proposal_stages values.
quoted_amountOptional. Numeric, β‰₯0.
current_roundOptional. Integer, β‰₯0.
JSON
{
  "project_id": 4,
  "title": "Revised foundation proposal round 2",
  "status": "draft",
  "quoted_amount": 2500000,
  "current_round": 2
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Updated",
  "data": {
    "id": 3,
    "business_id": 1,
    "project_id": 4,
    "project_name": "Block A",
    "title": "Revised foundation proposal round 2",
    "status": "draft",
    "quoted_amount": 2500000.0,
    "current_round": 2
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/proposals/{id}Tested

Permanently delete this proposal. Does not cascade-delete ProposalRound history β€” clean those up separately if needed.

Permission required
proposals.manage
Path parameters
ParamDescription
idRequired. Proposal ID. Must belong to the authenticated business β€” otherwise 404.
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": { "id": 3 }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ”

Proposal Rounds

GET/api/admin/proposal-roundsTested

Paginated list of proposal round history. Scoped to authenticated business. proposal_title is resolved via the proposal relation β€” never just proposal_id.

Permission required
proposals.view
Parameters
ParamDescription
proposal_idOptional. Restrict to rounds on one proposal β€” this is how the Admin Portal builds the round-history table on the Proposal Detail screen. No cross-business existence check is performed; a non-matching id simply yields zero rows.
statusOptional. Exact match on one of: pending, accepted, superseded.
searchOptional. Matches against notes OR the parent proposal's title (case-insensitive substring).
pageOptional. Default 1.
per_pageOptional. Default 20. Pass -1 for unpaginated.
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposal rounds",
  "data": [
    {
      "id": 3,
      "business_id": 1,
      "proposal_id": 1,
      "proposal_title": "Initial BOQ Proposal",
      "round_number": 3,
      "amount": 11800000.0,
      "status": "accepted",
      "notes": "Negotiation round 3",
      "submitted_at": "2026-05-29T18:20:54+00:00"
    },
    {
      "id": 2,
      "business_id": 1,
      "proposal_id": 1,
      "proposal_title": "Initial BOQ Proposal",
      "round_number": 2,
      "amount": 11500000.0,
      "status": "superseded",
      "notes": "Negotiation round 2",
      "submitted_at": "2026-04-29T18:20:54+00:00"
    }
  ],
  "pagination": {"current_page":1,"per_page":20,"total":3,"last_page":1}
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/proposal-roundsTested

Create a new proposal round record.

Permission required
proposals.manage
Request body
FieldDescription
proposal_idRequired. Integer β€” no existence check performed (matches the light-validation convention used by sibling FK fields such as Voucher's subcontractor_id).
round_numberRequired. Integer, β‰₯1. Should match the parent proposal's current_round once this round becomes the live one.
amountOptional. Numeric, β‰₯0.
statusOptional. String, max 32. One of pending (default), accepted, superseded.
notesOptional. Free text.
submitted_atOptional. Date. When this round's figure was shared with the client.
JSON
{
  "proposal_id": 1,
  "round_number": 4,
  "amount": 11750000,
  "status": "pending",
  "notes": "Final negotiated figure"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Created",
  "data": {
    "id": 4,
    "business_id": 1,
    "proposal_id": 1,
    "proposal_title": "Initial BOQ Proposal",
    "round_number": 4,
    "amount": 11750000.0,
    "status": "pending",
    "notes": "Final negotiated figure",
    "submitted_at": ""
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/proposal-rounds/{id}Tested

Retrieve one proposal round by ID.

Permission required
proposals.view
Path parameters
ParamDescription
idRequired. Proposal round ID. Must belong to the authenticated business β€” otherwise 404.
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposal rounds",
  "data": {
    "id": 4,
    "business_id": 1,
    "proposal_id": 1,
    "proposal_title": "Initial BOQ Proposal",
    "round_number": 4,
    "amount": 11750000.0,
    "status": "accepted",
    "notes": "Final negotiated figure",
    "submitted_at": ""
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/proposal-rounds/{id}Tested

Update any fields on an existing proposal round. All fields optional. Typical use: flip status to accepted or superseded.

Permission required
proposals.manage
Request body
FieldDescription
proposal_idOptional. Integer.
round_numberOptional. Integer, β‰₯1.
amountOptional. Numeric, β‰₯0.
statusOptional. String, max 32. One of pending, accepted, superseded.
notesOptional. Free text.
submitted_atOptional. Date.
JSON
{
  "status": "accepted"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Updated",
  "data": {
    "id": 4,
    "business_id": 1,
    "proposal_id": 1,
    "proposal_title": "Initial BOQ Proposal",
    "round_number": 4,
    "amount": 11750000.0,
    "status": "accepted",
    "notes": "Final negotiated figure",
    "submitted_at": ""
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/proposal-rounds/{id}Tested

Permanently delete this proposal round record.

Permission required
proposals.manage
Path parameters
ParamDescription
idRequired. Proposal round ID. Must belong to the authenticated business β€” otherwise 404.
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": {
    "id": 4
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ‘₯

Proposal Members

GET/api/admin/proposal-membersPlanned

List staff members assigned to a proposal. Scoped to authenticated business.

Permission required
proposals.view
Parameters
ParamDescription
proposal_idRequired. Filter by proposal.
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposal members",
  "data": [
    {
      "id": 1,
      "proposal_id": 1,
      "user_id": 7,
      "user_name": "Zainul Abideen",
      "role_label": "Lead Estimator",
      "assigned_at": "2026-03-15T10:00:00.000000Z"
    }
  ]
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/proposal-membersPlanned

Assign a staff member to a proposal.

Permission required
proposals.manage
Request body
JSON
{
  "proposal_id": 1,
  "user_id": 7,
  "role_label": "Lead Estimator"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Member assigned",
  "data": {
    "id": 1,
    "proposal_id": 1,
    "user_id": 7,
    "user_name": "Zainul Abideen",
    "role_label": "Lead Estimator",
    "assigned_at": "2026-08-11T09:00:00.000000Z"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
DELETE/api/admin/proposal-members/{id}Planned

Remove a staff member from a proposal.

Permission required
proposals.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": { "id": 1 }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ“

Proposal Notes

GET/api/admin/proposal-notesPlanned

List internal notes for a proposal. Not visible to the client. Scoped to authenticated business.

Permission required
proposals.view
Parameters
ParamDescription
proposal_idRequired. Filter by proposal.
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposal notes",
  "data": [
    {
      "id": 1,
      "proposal_id": 1,
      "author_id": 7,
      "author_name": "Zainul Abideen",
      "body": "Client pushed back on tile & marble budget β€” will itemise for round 2.",
      "created_at": "2026-03-28T10:15:00.000000Z",
      "updated_at": "2026-03-28T10:15:00.000000Z"
    }
  ]
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/proposal-notesPlanned

Add an internal note to a proposal.

Permission required
proposals.manage
Request body
JSON
{
  "proposal_id": 1,
  "body": "Client approved round 3 verbally β€” formal acceptance email expected EOD."
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Note saved",
  "data": {
    "id": 3,
    "proposal_id": 1,
    "author_id": 7,
    "author_name": "Zainul Abideen",
    "body": "Client approved round 3 verbally β€” formal acceptance email expected EOD.",
    "created_at": "2026-08-11T09:00:00.000000Z",
    "updated_at": "2026-08-11T09:00:00.000000Z"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
PUT/api/admin/proposal-notes/{id}Planned

Update an existing proposal note. Only the note author or an admin may edit.

Permission required
proposals.manage
Request body
JSON
{
  "body": "Updated note text."
}
Errors
401 Unauthenticated403 Forbidden404 Not found
DELETE/api/admin/proposal-notes/{id}Planned

Delete an internal note.

Permission required
proposals.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": { "id": 3 }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ’¬

Proposal Messages

GET/api/admin/proposal-messagesPlanned

List the client communication log for a proposal. Ordered oldest-first. Scoped to authenticated business.

Permission required
proposals.view
Parameters
ParamDescription
proposal_idRequired. Filter by proposal.
Response 200/201
JSON
{
  "success": true,
  "msg": "Proposal messages",
  "data": [
    {
      "id": 1,
      "proposal_id": 1,
      "direction": "outbound",
      "sender_name": "Zainul Abideen",
      "body": "Please find attached our initial BOQ proposal…",
      "sent_at": "2026-03-29T11:00:00.000000Z"
    },
    {
      "id": 2,
      "proposal_id": 1,
      "direction": "inbound",
      "sender_name": "Mr. Bilal Chaudhry",
      "body": "Thank you for the proposal. We'd like to defer the external cladding…",
      "sent_at": "2026-04-10T15:15:00.000000Z"
    }
  ]
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/proposal-messagesPlanned

Log an inbound or outbound client message against a proposal.

Permission required
proposals.manage
Request body
JSON
{
  "proposal_id": 1,
  "direction": "outbound",
  "sender_name": "Zainul Abideen",
  "body": "Please find the revised proposal (Round 2)…",
  "sent_at": "2026-04-29T10:30:00"
}
Field notes
FieldNotes
directionoutbound (team sent to client) or inbound (client sent to team)
sender_nameFree text β€” the name displayed in the message log
sent_atNullable. Defaults to now() if omitted.
Response 200/201
JSON
{
  "success": true,
  "msg": "Message logged",
  "data": {
    "id": 5,
    "proposal_id": 1,
    "direction": "outbound",
    "sender_name": "Zainul Abideen",
    "body": "Please find the revised proposal (Round 2)…",
    "sent_at": "2026-04-29T10:30:00.000000Z"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
πŸ“

Phases

GET/api/admin/phasesTested

Paginated list of phase. Scoped to authenticated business.

Permission required
phases.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Phases",
  "data": {
    "id": 5,
    "project_id": 4,
    "phase_key": "structural",
    "name": "Structural Framing",
    "status": "pending",
    "progress_percent": 0,
    "sort_order": 2
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/phasesTested

Create a new phase record.

Permission required
phases.manage
Request body
JSON
{
  "project_id": 4,
  "phase_key": "structural",
  "name": "Structural Framing",
  "status": "pending",
  "progress_percent": 0,
  "planned_start": "2026-08-01",
  "planned_end": "2026-10-15",
  "sort_order": 2
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Phases",
  "data": {
    "id": 5,
    "project_id": 4,
    "phase_key": "structural",
    "name": "Structural Framing",
    "status": "pending",
    "progress_percent": 0,
    "sort_order": 2
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/phases/{id}Tested

Retrieve one phase by ID.

Permission required
phases.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Phases",
  "data": {
    "id": 5,
    "project_id": 4,
    "phase_key": "structural",
    "name": "Structural Framing",
    "status": "pending",
    "progress_percent": 0,
    "sort_order": 2
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/phases/{id}Tested

Update any fields on an existing phase. All fields optional.

Permission required
phases.manage
Request body
JSON
{
  "project_id": 4,
  "phase_key": "structural",
  "name": "Structural Framing",
  "status": "pending",
  "progress_percent": 0,
  "planned_start": "2026-08-01",
  "planned_end": "2026-10-15",
  "sort_order": 2
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Phases",
  "data": {
    "id": 5,
    "project_id": 4,
    "phase_key": "structural",
    "name": "Structural Framing",
    "status": "pending",
    "progress_percent": 0,
    "sort_order": 2
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/phases/{id}Tested

Permanently delete this phase.

Permission required
phases.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ‘₯

People — Staff

GET/api/admin/staffTested

Paginated list of staff profile. Scoped to authenticated business.

Permission required
staff.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Staff",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": 7,
    "location_id": 1,
    "job_title": "Site Engineer",
    "department": "Engineering",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/staffTested

Create a new staff profile record.

Permission required
staff.manage
Request body
JSON
{
  "user_id": 7,
  "location_id": 1,
  "job_title": "Site Engineer",
  "department": "Engineering",
  "status": "active"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Staff",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": 7,
    "location_id": 1,
    "job_title": "Site Engineer",
    "department": "Engineering",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/staff/{id}Tested

Retrieve one staff profile by ID.

Permission required
staff.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Staff",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": 7,
    "location_id": 1,
    "job_title": "Site Engineer",
    "department": "Engineering",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/staff/{id}Tested

Update any fields on an existing staff profile. All fields optional.

Permission required
staff.manage
Request body
JSON
{
  "user_id": 7,
  "location_id": 1,
  "job_title": "Site Engineer",
  "department": "Engineering",
  "status": "active"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Staff",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": 7,
    "location_id": 1,
    "job_title": "Site Engineer",
    "department": "Engineering",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/staff/{id}Tested

Permanently delete this staff profile.

Permission required
staff.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ”§

People — Subcontractors

GET/api/admin/subcontractorsTested

Paginated list of subcontractor. Scoped to authenticated business.

Permission required
subcontractors.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractors",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": null,
    "company_name": "RapidSteel Contractors",
    "trade_type": "steel_works",
    "contact_email": "rapidsteel@contractors.test",
    "contact_phone": "+92-321-0011223",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/subcontractorsTested

Create a new subcontractor record.

Permission required
subcontractors.manage
Request body
JSON
{
  "user_id": null,
  "company_name": "RapidSteel Contractors",
  "trade_type": "steel_works",
  "contact_email": "rapidsteel@contractors.test",
  "contact_phone": "+92-321-0011223",
  "status": "active"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractors",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": null,
    "company_name": "RapidSteel Contractors",
    "trade_type": "steel_works",
    "contact_email": "rapidsteel@contractors.test",
    "contact_phone": "+92-321-0011223",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/subcontractors/{id}Tested

Retrieve one subcontractor by ID.

Permission required
subcontractors.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractors",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": null,
    "company_name": "RapidSteel Contractors",
    "trade_type": "steel_works",
    "contact_email": "rapidsteel@contractors.test",
    "contact_phone": "+92-321-0011223",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/subcontractors/{id}Tested

Update any fields on an existing subcontractor. All fields optional.

Permission required
subcontractors.manage
Request body
JSON
{
  "user_id": null,
  "company_name": "RapidSteel Contractors",
  "trade_type": "steel_works",
  "contact_email": "rapidsteel@contractors.test",
  "contact_phone": "+92-321-0011223",
  "status": "active"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractors",
  "data": {
    "id": 3,
    "business_id": 1,
    "user_id": null,
    "company_name": "RapidSteel Contractors",
    "trade_type": "steel_works",
    "contact_email": "rapidsteel@contractors.test",
    "contact_phone": "+92-321-0011223",
    "status": "active"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/subcontractors/{id}Tested

Permanently delete this subcontractor.

Permission required
subcontractors.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
🧾

Financial — Vouchers

GET/api/admin/vouchersTested

Paginated list of voucher. Scoped to authenticated business.

Permission required
vouchers.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Vouchers",
  "data": {
    "id": 8,
    "business_id": 1,
    "project_id": 4,
    "subcontractor_id": 3,
    "voucher_no": "VCH-2026-0008",
    "voucher_type": "subcontractor",
    "status": "draft",
    "amount": 220000.0,
    "week_ending": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/vouchersTested

Create a new voucher record.

Permission required
vouchers.manage
Request body
JSON
{
  "project_id": 4,
  "subcontractor_id": 3,
  "voucher_no": "VCH-2026-0008",
  "voucher_type": "subcontractor",
  "status": "draft",
  "amount": 220000,
  "week_ending": "2026-06-28"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Vouchers",
  "data": {
    "id": 8,
    "business_id": 1,
    "project_id": 4,
    "subcontractor_id": 3,
    "voucher_no": "VCH-2026-0008",
    "voucher_type": "subcontractor",
    "status": "draft",
    "amount": 220000.0,
    "week_ending": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/vouchers/{id}Tested

Retrieve one voucher by ID.

Permission required
vouchers.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Vouchers",
  "data": {
    "id": 8,
    "business_id": 1,
    "project_id": 4,
    "subcontractor_id": 3,
    "voucher_no": "VCH-2026-0008",
    "voucher_type": "subcontractor",
    "status": "draft",
    "amount": 220000.0,
    "week_ending": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/vouchers/{id}Tested

Update any fields on an existing voucher. All fields optional.

Permission required
vouchers.manage
Request body
JSON
{
  "project_id": 4,
  "subcontractor_id": 3,
  "voucher_no": "VCH-2026-0008",
  "voucher_type": "subcontractor",
  "status": "draft",
  "amount": 220000,
  "week_ending": "2026-06-28"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Vouchers",
  "data": {
    "id": 8,
    "business_id": 1,
    "project_id": 4,
    "subcontractor_id": 3,
    "voucher_no": "VCH-2026-0008",
    "voucher_type": "subcontractor",
    "status": "draft",
    "amount": 220000.0,
    "week_ending": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/vouchers/{id}Tested

Permanently delete this voucher.

Permission required
vouchers.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ“’

Financial — Ledger Entries

GET/api/admin/ledgersTested

Paginated list of ledger entry. Scoped to authenticated business.

Permission required
ledgers.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Ledgers",
  "data": {
    "id": 4,
    "business_id": 1,
    "project_id": 4,
    "party_type": "subcontractor",
    "party_id": 3,
    "entry_type": "payment",
    "debit": 0.0,
    "credit": 220000.0,
    "reference": "VCH-2026-0008",
    "description": "Payment against voucher",
    "entry_date": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/ledgersTested

Create a new ledger entry record.

Permission required
ledgers.manage
Request body
JSON
{
  "project_id": 4,
  "party_type": "subcontractor",
  "party_id": 3,
  "entry_type": "payment",
  "debit": 0,
  "credit": 220000,
  "reference": "VCH-2026-0008",
  "description": "Payment against voucher",
  "entry_date": "2026-06-28"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Ledgers",
  "data": {
    "id": 4,
    "business_id": 1,
    "project_id": 4,
    "party_type": "subcontractor",
    "party_id": 3,
    "entry_type": "payment",
    "debit": 0.0,
    "credit": 220000.0,
    "reference": "VCH-2026-0008",
    "description": "Payment against voucher",
    "entry_date": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/ledgers/{id}Tested

Retrieve one ledger entry by ID.

Permission required
ledgers.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Ledgers",
  "data": {
    "id": 4,
    "business_id": 1,
    "project_id": 4,
    "party_type": "subcontractor",
    "party_id": 3,
    "entry_type": "payment",
    "debit": 0.0,
    "credit": 220000.0,
    "reference": "VCH-2026-0008",
    "description": "Payment against voucher",
    "entry_date": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/ledgers/{id}Tested

Update any fields on an existing ledger entry. All fields optional.

Permission required
ledgers.manage
Request body
JSON
{
  "project_id": 4,
  "party_type": "subcontractor",
  "party_id": 3,
  "entry_type": "payment",
  "debit": 0,
  "credit": 220000,
  "reference": "VCH-2026-0008",
  "description": "Payment against voucher",
  "entry_date": "2026-06-28"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Ledgers",
  "data": {
    "id": 4,
    "business_id": 1,
    "project_id": 4,
    "party_type": "subcontractor",
    "party_id": 3,
    "entry_type": "payment",
    "debit": 0.0,
    "credit": 220000.0,
    "reference": "VCH-2026-0008",
    "description": "Payment against voucher",
    "entry_date": "2026-06-28"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/ledgers/{id}Tested

Permanently delete this ledger entry.

Permission required
ledgers.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ”€

Financial — Variation Orders

GET/api/admin/variation-ordersTested

Paginated list of variation order. Scoped to authenticated business.

Permission required
variation_orders.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Variation orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "vo_number": "VO-2026-0001",
    "title": "Additional reinforcement for column footings",
    "description": "Structural engineer requirement after soil report",
    "amount": 75000.0,
    "status": "pending"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/variation-ordersTested

Create a new variation order record.

Permission required
variation_orders.manage
Request body
JSON
{
  "project_id": 4,
  "vo_number": "VO-2026-0001",
  "title": "Additional reinforcement for column footings",
  "description": "Structural engineer requirement after soil report",
  "amount": 75000,
  "status": "pending"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Variation orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "vo_number": "VO-2026-0001",
    "title": "Additional reinforcement for column footings",
    "description": "Structural engineer requirement after soil report",
    "amount": 75000.0,
    "status": "pending"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/variation-orders/{id}Tested

Retrieve one variation order by ID.

Permission required
variation_orders.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Variation orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "vo_number": "VO-2026-0001",
    "title": "Additional reinforcement for column footings",
    "description": "Structural engineer requirement after soil report",
    "amount": 75000.0,
    "status": "pending"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/variation-orders/{id}Tested

Update any fields on an existing variation order. All fields optional.

Permission required
variation_orders.manage
Request body
JSON
{
  "project_id": 4,
  "vo_number": "VO-2026-0001",
  "title": "Additional reinforcement for column footings",
  "description": "Structural engineer requirement after soil report",
  "amount": 75000,
  "status": "pending"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Variation orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "vo_number": "VO-2026-0001",
    "title": "Additional reinforcement for column footings",
    "description": "Structural engineer requirement after soil report",
    "amount": 75000.0,
    "status": "pending"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/variation-orders/{id}Tested

Permanently delete this variation order.

Permission required
variation_orders.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ“…

Financial — Daywork Orders

GET/api/admin/daywork-ordersTested

Paginated list of daywork order. Scoped to authenticated business.

Permission required
daywork_orders.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Daywork orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "dwo_number": "DWO-2026-0001",
    "title": "Emergency waterproofing works",
    "description": "Urgent waterproofing after rain damage",
    "amount": 32000.0,
    "status": "draft",
    "work_date": "2026-06-22"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/daywork-ordersTested

Create a new daywork order record.

Permission required
daywork_orders.manage
Request body
JSON
{
  "project_id": 4,
  "dwo_number": "DWO-2026-0001",
  "title": "Emergency waterproofing works",
  "description": "Urgent waterproofing after rain damage",
  "amount": 32000,
  "status": "draft",
  "work_date": "2026-06-22"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Daywork orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "dwo_number": "DWO-2026-0001",
    "title": "Emergency waterproofing works",
    "description": "Urgent waterproofing after rain damage",
    "amount": 32000.0,
    "status": "draft",
    "work_date": "2026-06-22"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/daywork-orders/{id}Tested

Retrieve one daywork order by ID.

Permission required
daywork_orders.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Daywork orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "dwo_number": "DWO-2026-0001",
    "title": "Emergency waterproofing works",
    "description": "Urgent waterproofing after rain damage",
    "amount": 32000.0,
    "status": "draft",
    "work_date": "2026-06-22"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/daywork-orders/{id}Tested

Update any fields on an existing daywork order. All fields optional.

Permission required
daywork_orders.manage
Request body
JSON
{
  "project_id": 4,
  "dwo_number": "DWO-2026-0001",
  "title": "Emergency waterproofing works",
  "description": "Urgent waterproofing after rain damage",
  "amount": 32000,
  "status": "draft",
  "work_date": "2026-06-22"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Daywork orders",
  "data": {
    "id": 1,
    "business_id": 1,
    "project_id": 4,
    "dwo_number": "DWO-2026-0001",
    "title": "Emergency waterproofing works",
    "description": "Urgent waterproofing after rain damage",
    "amount": 32000.0,
    "status": "draft",
    "work_date": "2026-06-22"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/daywork-orders/{id}Tested

Permanently delete this daywork order.

Permission required
daywork_orders.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
πŸ“†

Calendar Events

GET/api/admin/calendarTested

Paginated list of calendar event. Scoped to authenticated business.

Permission required
calendar.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Calendar",
  "data": {
    "id": 5,
    "business_id": 1,
    "project_id": 4,
    "assigned_user_id": 7,
    "title": "Foundation inspection",
    "description": "Structural engineer site visit for foundation sign-off",
    "starts_at": "2026-07-05T09:00:00+05:00",
    "ends_at": "2026-07-05T12:00:00+05:00",
    "event_type": "inspection"
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/calendarTested

Create a new calendar event record.

Permission required
calendar.manage
Request body
JSON
{
  "project_id": 4,
  "assigned_user_id": 7,
  "title": "Foundation inspection",
  "description": "Structural engineer site visit for foundation sign-off",
  "starts_at": "2026-07-05T09:00:00+05:00",
  "ends_at": "2026-07-05T12:00:00+05:00",
  "event_type": "inspection"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Calendar",
  "data": {
    "id": 5,
    "business_id": 1,
    "project_id": 4,
    "assigned_user_id": 7,
    "title": "Foundation inspection",
    "description": "Structural engineer site visit for foundation sign-off",
    "starts_at": "2026-07-05T09:00:00+05:00",
    "ends_at": "2026-07-05T12:00:00+05:00",
    "event_type": "inspection"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/calendar/{id}Tested

Retrieve one calendar event by ID.

Permission required
calendar.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Calendar",
  "data": {
    "id": 5,
    "business_id": 1,
    "project_id": 4,
    "assigned_user_id": 7,
    "title": "Foundation inspection",
    "description": "Structural engineer site visit for foundation sign-off",
    "starts_at": "2026-07-05T09:00:00+05:00",
    "ends_at": "2026-07-05T12:00:00+05:00",
    "event_type": "inspection"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/calendar/{id}Tested

Update any fields on an existing calendar event. All fields optional.

Permission required
calendar.manage
Request body
JSON
{
  "project_id": 4,
  "assigned_user_id": 7,
  "title": "Foundation inspection",
  "description": "Structural engineer site visit for foundation sign-off",
  "starts_at": "2026-07-05T09:00:00+05:00",
  "ends_at": "2026-07-05T12:00:00+05:00",
  "event_type": "inspection"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Calendar",
  "data": {
    "id": 5,
    "business_id": 1,
    "project_id": 4,
    "assigned_user_id": 7,
    "title": "Foundation inspection",
    "description": "Structural engineer site visit for foundation sign-off",
    "starts_at": "2026-07-05T09:00:00+05:00",
    "ends_at": "2026-07-05T12:00:00+05:00",
    "event_type": "inspection"
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/calendar/{id}Tested

Permanently delete this calendar event.

Permission required
calendar.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
βš™

Setup & Reference Data

Configure these during business onboarding before creating projects. Each follows the standard 5-endpoint CRUD pattern scoped to the business.

GET/api/admin/locationsTested

Paginated list of location. Scoped to authenticated business.

Permission required
locations.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Locations",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Karachi Office",
    "address": "Plot 14, SITE Area, Karachi",
    "contact_person": "Usman Ali",
    "contact_phone": "+92-300-4455667",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/locationsTested

Create a new location record.

Permission required
locations.manage
Request body
JSON
{
  "name": "Karachi Office",
  "address": "Plot 14, SITE Area, Karachi",
  "contact_person": "Usman Ali",
  "contact_phone": "+92-300-4455667",
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Locations",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Karachi Office",
    "address": "Plot 14, SITE Area, Karachi",
    "contact_person": "Usman Ali",
    "contact_phone": "+92-300-4455667",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/locations/{id}Tested

Retrieve one location by ID.

Permission required
locations.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Locations",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Karachi Office",
    "address": "Plot 14, SITE Area, Karachi",
    "contact_person": "Usman Ali",
    "contact_phone": "+92-300-4455667",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/locations/{id}Tested

Update any fields on an existing location. All fields optional.

Permission required
locations.manage
Request body
JSON
{
  "name": "Karachi Office",
  "address": "Plot 14, SITE Area, Karachi",
  "contact_person": "Usman Ali",
  "contact_phone": "+92-300-4455667",
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Locations",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Karachi Office",
    "address": "Plot 14, SITE Area, Karachi",
    "contact_person": "Usman Ali",
    "contact_phone": "+92-300-4455667",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/locations/{id}Tested

Permanently delete this location.

Permission required
locations.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/phase-libraryTested

Paginated list of phase library item. Scoped to authenticated business.

Permission required
phase_library.view
Parameters
ParamDescription
searchText search
categoryFilter by category slug (e.g. civil_structural, mep_rough_in)
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Phase library",
  "data": {
    "id": 5,
    "business_id": 1,
    "phase_key": "electrical",
    "category": "civil_structural",
    "name": "Electrical Works",
    "description": "Full electrical wiring, panel installation, fixtures",
    "default_duration_days": 45,
    "sort_order": 5,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/phase-libraryTested

Create a new phase library item record.

Permission required
phase_library.manage
Request body
JSON
{
  "phase_key": "electrical",
    "category": "civil_structural",
  "name": "Electrical Works",
  "description": "Full electrical wiring, panel installation, fixtures",
  "default_duration_days": 45,
  "sort_order": 5,
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Phase library",
  "data": {
    "id": 5,
    "business_id": 1,
    "phase_key": "electrical",
    "category": "civil_structural",
    "name": "Electrical Works",
    "description": "Full electrical wiring, panel installation, fixtures",
    "default_duration_days": 45,
    "sort_order": 5,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/phase-library/{id}Tested

Retrieve one phase library item by ID.

Permission required
phase_library.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Phase library",
  "data": {
    "id": 5,
    "business_id": 1,
    "phase_key": "electrical",
    "category": "civil_structural",
    "name": "Electrical Works",
    "description": "Full electrical wiring, panel installation, fixtures",
    "default_duration_days": 45,
    "sort_order": 5,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/phase-library/{id}Tested

Update any fields on an existing phase library item. All fields optional.

Permission required
phase_library.manage
Request body
JSON
{
  "phase_key": "electrical",
    "category": "civil_structural",
  "name": "Electrical Works",
  "description": "Full electrical wiring, panel installation, fixtures",
  "default_duration_days": 45,
  "sort_order": 5,
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Phase library",
  "data": {
    "id": 5,
    "business_id": 1,
    "phase_key": "electrical",
    "category": "civil_structural",
    "name": "Electrical Works",
    "description": "Full electrical wiring, panel installation, fixtures",
    "default_duration_days": 45,
    "sort_order": 5,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/phase-library/{id}Tested

Permanently delete this phase library item.

Permission required
phase_library.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/document-typesTested

Paginated list of document type. Scoped to authenticated business.

Permission required
document_types.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Document types",
  "data": {
    "id": 3,
    "business_id": 1,
    "name": "Completion Certificate",
    "category": "certification",
    "requires_approval": true,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/document-typesTested

Create a new document type record.

Permission required
document_types.manage
Request body
JSON
{
  "name": "Completion Certificate",
  "category": "certification",
  "requires_approval": true,
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Document types",
  "data": {
    "id": 3,
    "business_id": 1,
    "name": "Completion Certificate",
    "category": "certification",
    "requires_approval": true,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/document-types/{id}Tested

Retrieve one document type by ID.

Permission required
document_types.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Document types",
  "data": {
    "id": 3,
    "business_id": 1,
    "name": "Completion Certificate",
    "category": "certification",
    "requires_approval": true,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/document-types/{id}Tested

Update any fields on an existing document type. All fields optional.

Permission required
document_types.manage
Request body
JSON
{
  "name": "Completion Certificate",
  "category": "certification",
  "requires_approval": true,
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Document types",
  "data": {
    "id": 3,
    "business_id": 1,
    "name": "Completion Certificate",
    "category": "certification",
    "requires_approval": true,
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/document-types/{id}Tested

Permanently delete this document type.

Permission required
document_types.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/trade-typesTested

Paginated list of trade type. Scoped to authenticated business.

Permission required
trade_types.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Trade types",
  "data": {
    "id": 4,
    "business_id": 1,
    "name": "Structural Steel Works",
    "code": "SSW",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/trade-typesTested

Create a new trade type record.

Permission required
trade_types.manage
Request body
JSON
{
  "name": "Structural Steel Works",
  "code": "SSW",
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Trade types",
  "data": {
    "id": 4,
    "business_id": 1,
    "name": "Structural Steel Works",
    "code": "SSW",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/trade-types/{id}Tested

Retrieve one trade type by ID.

Permission required
trade_types.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Trade types",
  "data": {
    "id": 4,
    "business_id": 1,
    "name": "Structural Steel Works",
    "code": "SSW",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/trade-types/{id}Tested

Update any fields on an existing trade type. All fields optional.

Permission required
trade_types.manage
Request body
JSON
{
  "name": "Structural Steel Works",
  "code": "SSW",
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Trade types",
  "data": {
    "id": 4,
    "business_id": 1,
    "name": "Structural Steel Works",
    "code": "SSW",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/trade-types/{id}Tested

Permanently delete this trade type.

Permission required
trade_types.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/subcontractor-categoriesTested

Paginated list of subcontractor category. Scoped to authenticated business.

Permission required
subcontractor_categories.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractor categories",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Civil Works",
    "code": "CIV",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/subcontractor-categoriesTested

Create a new subcontractor category record.

Permission required
subcontractor_categories.manage
Request body
JSON
{
  "name": "Civil Works",
  "code": "CIV",
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractor categories",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Civil Works",
    "code": "CIV",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/subcontractor-categories/{id}Tested

Retrieve one subcontractor category by ID.

Permission required
subcontractor_categories.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractor categories",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Civil Works",
    "code": "CIV",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/subcontractor-categories/{id}Tested

Update any fields on an existing subcontractor category. All fields optional.

Permission required
subcontractor_categories.manage
Request body
JSON
{
  "name": "Civil Works",
  "code": "CIV",
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Subcontractor categories",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Civil Works",
    "code": "CIV",
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/subcontractor-categories/{id}Tested

Permanently delete this subcontractor category.

Permission required
subcontractor_categories.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
GET/api/admin/project-templatesTested

Paginated list of project template. Scoped to authenticated business.

Permission required
project_templates.view
Parameters
ParamDescription
searchText search
per_pageDefault 20
Response 200/201
JSON
{
  "success": true,
  "msg": "Project templates",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Residential Construction Standard",
    "description": "Standard phases for a residential build",
    "phase_keys": ["foundation","structural","roofing","plumbing","electrical","finishing"],
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/project-templatesTested

Create a new project template record.

Permission required
project_templates.manage
Request body
JSON
{
  "name": "Residential Construction Standard",
  "description": "Standard phases for a residential build",
  "phase_keys": ["foundation","structural","roofing","plumbing","electrical","finishing"],
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Project templates",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Residential Construction Standard",
    "description": "Standard phases for a residential build",
    "phase_keys": ["foundation","structural","roofing","plumbing","electrical","finishing"],
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
GET/api/admin/project-templates/{id}Tested

Retrieve one project template by ID.

Permission required
project_templates.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Project templates",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Residential Construction Standard",
    "description": "Standard phases for a residential build",
    "phase_keys": ["foundation","structural","roofing","plumbing","electrical","finishing"],
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found
PUT/api/admin/project-templates/{id}Tested

Update any fields on an existing project template. All fields optional.

Permission required
project_templates.manage
Request body
JSON
{
  "name": "Residential Construction Standard",
  "description": "Standard phases for a residential build",
  "phase_keys": ["foundation","structural","roofing","plumbing","electrical","finishing"],
  "is_active": true
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Project templates",
  "data": {
    "id": 2,
    "business_id": 1,
    "name": "Residential Construction Standard",
    "description": "Standard phases for a residential build",
    "phase_keys": ["foundation","structural","roofing","plumbing","electrical","finishing"],
    "is_active": true
  }
}
Errors
401 Unauthenticated403 Forbidden404 Not found422 Validation failed
DELETE/api/admin/project-templates/{id}Tested

Permanently delete this project template.

Permission required
project_templates.manage
Response 200/201
JSON
{
  "success": true,
  "msg": "Deleted",
  "data": null
}
Errors
401 Unauthenticated403 Forbidden404 Not found
✍

Settings — Signature

GET/api/admin/signature-settingsTested

Get the business-level signature settings used on vouchers, certificates, and documents.

Permission required
settings.view
Response 200/201
JSON
{
  "success": true,
  "msg": "Signature settings",
  "data": {
    "id": 1,
    "business_id": 1,
    "user_id": 0,
    "signature_image_path": "signatures/business-1-default.png",
    "signer_name": "Eng. Arif Khan",
    "signer_title": "Director - Pak Engineering Service"
  }
}
Errors
401 Unauthenticated403 Forbidden
PUT/api/admin/signature-settingsTested

Update/upsert the business signature. Creates the record if it does not yet exist.

Permission required
settings.manage
Request body
JSON
{
  "signature_image_path": "signatures/business-1-default.png",
  "signer_name": "Eng. Arif Khan",
  "signer_title": "Director - Pak Engineering Service"
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Signature settings",
  "data": {
    "id": 1,
    "business_id": 1,
    "user_id": 0,
    "signature_image_path": "signatures/business-1-default.png",
    "signer_name": "Eng. Arif Khan",
    "signer_title": "Director - Pak Engineering Service"
  }
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
πŸ””

Notifications (Bell Dropdown)

GET/api/admin/notificationsImplemented

Bell-dropdown endpoint. Returns up to 20 most recent unread notifications for the authenticated user. Available to both admin and staff. No pagination key β€” designed for lightweight bell polling.

Permission required
admin or staff role
No query parameters
Response 200
JSON
{
  "success": true,
  "msg": "Notifications",
  "data": [
    {
      "id": 12,
      "type": "project_created",
      "title": "New Project Created",
      "body": "Residential Block A has been created and assigned to you.",
      "is_read": false,
      "data": { "project_id": 5 },
      "created_at": "2026-07-01T09:14:00+05:00"
    },
    {
      "id": 11,
      "type": "phase_updated",
      "title": "Phase Status Changed",
      "body": "Foundation Work phase marked as complete.",
      "is_read": false,
      "data": { "phase_id": 18 },
      "created_at": "2026-07-01T08:30:00+05:00"
    }
  ]
}
Errors
401 Unauthenticated403 Non-admin/staff role
PATCH/api/admin/notifications/read-allImplemented

Marks all unread notifications as read for the authenticated user. Used when the user opens the bell dropdown and dismisses it.

Permission required
admin or staff role
No request body required
Response 200
JSON
{ "success": true, "msg": "All marked read", "data": null }
Errors
401 Unauthenticated403 Forbidden
πŸ“‹

Audit Logs (Admin Only)

GET/api/admin/audit-logsImplemented

Paginated full history of all notifications/audit events for the authenticated admin user. Admin only β€” staff get 403. Supports filter by type, is_read, and text search across title, body, type.

Permission required
admin role only
Query parameters
ParamTypeDescription
typestringFilter by notification type (e.g. project_created, phase_updated)
is_read0/1/true/falseFilter unread or read entries
searchstringFull-text search on title, body, type, and numeric id
per_pageintDefault 15
Response 200
JSON
{
  "success": true,
  "msg": "Audit logs",
  "data": [
    {
      "id": 12,
      "type": "project_created",
      "title": "New Project Created",
      "body": "Residential Block A has been created and assigned to you.",
      "is_read": true,
      "data": { "project_id": 5 },
      "created_at": "2026-07-01T09:14:00+05:00"
    }
  ],
  "pagination": { "total": 48, "per_page": 15, "current_page": 1, "last_page": 4 }
}
Errors
401 Unauthenticated403 Staff or non-admin role
GET/api/admin/audit-logs/{id}Implemented

Returns a single audit log entry scoped to the authenticated admin's own records.

Permission required
admin role only
Response 200
JSON
{
  "success": true,
  "msg": "Audit log",
  "data": {
    "id": 12, "type": "project_created", "title": "New Project Created",
    "body": "Residential Block A has been created and assigned to you.",
    "is_read": true, "data": { "project_id": 5 },
    "created_at": "2026-07-01T09:14:00+05:00"
  }
}
Errors
404 Not found403 Admin only
PATCH/api/admin/audit-logs/read-allImplemented

Marks all unread audit log entries as read for the authenticated admin.

Permission required
admin role only
Response 200
JSON
{ "success": true, "msg": "All marked read", "data": null }
Errors
403 Admin only
PATCH/api/admin/audit-logs/{id}/readImplemented

Marks a single audit log entry as read by id. Scoped to the authenticated admin's records.

Permission required
admin role only
Response 200
JSON
{ "success": true, "msg": "Marked read", "data": { "id": 12, "is_read": true } }
Errors
404 Not found403 Admin only
DELETE/api/admin/audit-logs/{id}Implemented

Hard-deletes a single audit log entry. Admin only. Record must belong to the authenticated user.

Permission required
admin role only
⚠ Permanent deletion β€” no soft delete or recovery.
Response 200
JSON
{ "success": true, "msg": "Deleted", "data": null }
Errors
404 Not found403 Admin only
πŸ›‘

Roles & Permissions

GET/api/admin/rolesImplemented

List all roles with their assigned permissions.

Permission required
manage_roles
Response 200/201
JSON
{
  "success": true,
  "msg": "Roles",
  "data": [
    {
      "id": 1,
      "slug": "admin",
      "name": "Business Admin",
      "is_system": true,
      "permissions": [
        {"id": 1, "slug": "projects.view", "name": "View Projects"},
        {"id": 2, "slug": "projects.manage", "name": "Manage Projects"},
        {"id": 3, "slug": "dashboard.view", "name": "View Dashboard"}
      ]
    },
    {
      "id": 3,
      "slug": "site-supervisor",
      "name": "Site Supervisor",
      "is_system": false,
      "permissions": [
        {"id": 1, "slug": "projects.view", "name": "View Projects"},
        {"id": 5, "slug": "phases.view", "name": "View Phases"}
      ]
    }
  ]
}
Errors
401 Unauthenticated403 Forbidden
POST/api/admin/rolesImplemented

Create a custom role with specified permission IDs.

Permission required
manage_roles
Request body
JSON
{
  "name": "Site Supervisor",
  "permission_ids": [1, 5, 9, 13]
}
Response 200/201
JSON
{
  "success": true,
  "msg": "Roles",
  "data": [
    {
      "id": 1,
      "slug": "admin",
      "name": "Business Admin",
      "is_system": true,
      "permissions": [
        {"id": 1, "slug": "projects.view", "name": "View Projects"},
        {"id": 2, "slug": "projects.manage", "name": "Manage Projects"},
        {"id": 3, "slug": "dashboard.view", "name": "View Dashboard"}
      ]
    },
    {
      "id": 3,
      "slug": "site-supervisor",
      "name": "Site Supervisor",
      "is_system": false,
      "permissions": [
        {"id": 1, "slug": "projects.view", "name": "View Projects"},
        {"id": 5, "slug": "phases.view", "name": "View Phases"}
      ]
    }
  ]
}
Errors
401 Unauthenticated403 Forbidden422 Validation failed
πŸ”

Common Lookups

GET/api/common/projectsTested

Get business-scoped projects lookup list.

Parameters
ParamDescription
searchOptional name filter
statusOptional status filter
Response 200
JSON
{
  "success": true,
  "msg": "Projects",
  "data": [
    {
      "id": "1",
      "name": "Residential Block A",
      "status": "proposal",
      "location_name": "Karachi Office"
    }
  ]
}
GET/api/common/locationsTested

Get business-scoped locations lookup list.

Parameters
ParamDescription
searchOptional name filter
Response 200
JSON
{
  "success": true,
  "msg": "Locations",
  "data": [
    {
      "id": "1",
      "name": "Karachi Office",
      "address": "Plot 14, SITE Area, Karachi"
    }
  ]
}
GET/api/common/staffTested

Get business-scoped staff lookup list.

Parameters
ParamDescription
searchOptional display name filter
Response 200
JSON
{
  "success": true,
  "msg": "Staff",
  "data": [
    {
      "id": "1",
      "name": "Zahid Khan",
      "trade_type": "Civil",
      "role": ""
    }
  ]
}
GET/api/common/subcontractorsTested

Get business-scoped subcontractors lookup list.

Parameters
ParamDescription
searchOptional company name filter
category_idOptional category filter
Response 200
JSON
{
  "success": true,
  "msg": "Subcontractors",
  "data": [
    {
      "id": "1",
      "name": "RapidSteel Contractors",
      "category_name": "Structure",
      "trade_type": "Civil"
    }
  ]
}
GET/api/common/subcontractor-categoriesTested

Get business-scoped subcontractor categories lookup list.

Parameters
ParamDescription
searchOptional name filter
Response 200
JSON
{
  "success": true,
  "msg": "Subcontractor categories",
  "data": [
    {
      "id": "1",
      "name": "Structure"
    }
  ]
}
GET/api/common/project-templatesTested

Get business-scoped project templates lookup list.

Parameters
ParamDescription
searchOptional name filter
Response 200
JSON
{
  "success": true,
  "msg": "Project templates",
  "data": [
    {
      "id": "1",
      "name": "Residential Standard"
    }
  ]
}
GET/api/common/phasesTested

Get business-scoped project phases lookup list (requires project_id).

Parameters
ParamDescription
project_idRequired project ID
searchOptional name filter
Response 200
JSON
{
  "success": true,
  "msg": "Phases",
  "data": [
    {
      "id": "1",
      "name": "Foundation",
      "phase_key": "foundation",
      "status": "pending"
    }
  ]
}
GET/api/common/materialsTested

Get business-scoped materials lookup list (requires project_id).

Parameters
ParamDescription
project_idRequired project ID
searchOptional name filter
Response 200
JSON
{
  "success": true,
  "msg": "Materials",
  "data": [
    {
      "id": "1",
      "name": "Steel Rebars",
      "unit": "tons"
    }
  ]
}
GET/api/common/rolesTested

Get business-scoped roles lookup list.

Parameters
ParamDescription
searchOptional name filter
Response 200
JSON
{
  "success": true,
  "msg": "Roles",
  "data": [
    {
      "id": "1",
      "name": "Site Supervisor"
    }
  ]
}
GET/api/common/plan-tiersTested

Get list of active subscription plan tiers.

Response 200
JSON
{
  "success": true,
  "msg": "Plan tiers",
  "data": [
    {
      "id": "1",
      "name": "Basic"
    },
    {
      "id": "2",
      "name": "Pro"
    }
  ]
}
GET/api/common/subscription-plansTested

Get list of active subscription plans with concatenated price label.

Response 200
JSON
{
  "success": true,
  "msg": "Subscription plans",
  "data": [
    {
      "id": "1",
      "name": "Pro ($99/mo)"
    }
  ]
}
GET/api/common/project-typesTested

Get project types lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Project types",
  "data": [
    {
      "id": "1",
      "name": "Residential"
    }
  ]
}
GET/api/common/expense-categoriesTested

Get expense categories lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Expense categories",
  "data": [
    {
      "id": "1",
      "name": "Labor"
    }
  ]
}
GET/api/common/advance-sourcesTested

Get advance sources lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Advance sources",
  "data": [
    {
      "id": "1",
      "name": "Client (paid directly to contractor)"
    }
  ]
}
GET/api/common/daywork-expense-policiesTested

Get daywork expense policies lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Daywork expense policies",
  "data": [
    {
      "id": "1",
      "name": "Client pays all (wages + all expenses)"
    }
  ]
}
GET/api/common/proposal-packagesTested

Get proposal packages lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Proposal packages",
  "data": [
    {
      "id": "1",
      "name": "Basic"
    }
  ]
}
GET/api/common/proposal-stagesTested

Get proposal stages lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Proposal stages",
  "data": [
    {
      "id": "1",
      "name": "Draft"
    }
  ]
}
GET/api/common/voucher-statusesTested

Get voucher statuses lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Voucher statuses",
  "data": [
    {
      "id": "1",
      "name": "Draft"
    }
  ]
}
GET/api/common/phase-statusesTested

Get phase statuses lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Phase statuses",
  "data": [
    {
      "id": "1",
      "name": "Not Started"
    }
  ]
}
GET/api/common/task-statusesTested

Get task statuses lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Task statuses",
  "data": [
    {
      "id": "1",
      "name": "In Progress"
    }
  ]
}
GET/api/common/theme-colorsTested

Get theme colors lookup list with hex values.

Response 200
JSON
{
  "success": true,
  "msg": "Theme colors",
  "data": [
    {
      "id": "1",
      "name": "Amber (Safety Orange)",
      "hex_value": "#F59E0B"
    }
  ]
}
GET/api/common/theme-modesTested

Get theme modes lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Theme modes",
  "data": [
    {
      "id": "1",
      "name": "Dark Mode"
    }
  ]
}
GET/api/common/languagesTested

Get languages lookup list with ISO code as id.

Response 200
JSON
{
  "success": true,
  "msg": "Languages",
  "data": [
    {
      "id": "en",
      "name": "English"
    }
  ]
}
GET/api/common/landing-content-modesTested

Get landing content modes lookup list.

Response 200
JSON
{
  "success": true,
  "msg": "Landing content modes",
  "data": [
    {
      "id": "1",
      "name": "Automatic (latest)"
    }
  ]
}