Pest Control API

A powerful, secure, and flexible API for managing pest control operations. Automate scheduling, manage clients, and generate quotes with ease.

Client Management

Full CRUD operations for managing client profiles and history.

Smart Quoting

Generate detailed quotes with material costs and labor calculations.

Scheduling

Efficiently manage appointments and technician assignments.

Inventory

Track material usage and stock levels in real-time.

Getting Started

The Pest Control API is built around RESTful principles. It uses standard HTTP verbs, returns JSON-encoded responses, and uses standard HTTP response codes.

Base URL
All API requests should be made to:
https://pest-control-backend-development.up.railway.app

Conventions

Response Format

All responses are wrapped in a standard envelope to ensure consistency.

JSON Structure
{
  "data": { ... },      // The requested resource(s)
  "message": "...",     // Human-readable message
  "meta": { ... }       // Pagination or other metadata
}

Pagination

List endpoints support pagination via the page and per_page query parameters.

Rate Limiting

To ensure service stability, the API is rate-limited. You can make up to 60 requests per minute. Check the X-RateLimit-* headers in the response for your current status.

Prerequisite Knowledge

Before integrating with this API, you should be familiar with the following concepts:

  • RESTful APIs: Understanding of HTTP methods (GET, POST, PUT, DELETE) and status codes.
  • JSON: The API accepts and returns data in JSON format.
  • Authentication: Knowledge of Bearer Token authentication headers.

Authentication Overview

The PestControl API uses Laravel Sanctum to provide a secure, token-based authentication system. This ensures that your data remains protected and that only authorized users can perform actions.

Security Notice
Never share your API tokens. If a token is compromised, revoke it immediately.

Obtaining Tokens

To access protected endpoints, you must first obtain an API token. This is done by exchanging your credentials (email and password) for a token via the Login endpoint.

Once you successfully log in, the API will return a plain-text token. Store this token securely.

Using Tokens

Include the token in the Authorization header of your HTTP requests. The token must be prefixed with Bearer.

Header Format
HTTP Header
Authorization: Bearer <your_token_here>

Handling Errors

If your request is missing a token, or if the token is invalid or expired, the API will return a 401 Unauthorized response.

401 Response
{
                                            "message": "Unauthenticated."
                                        }

Authentication

Sign in, registration by invitation, password reset and the signed-in user. Login, register, API key, forgot and reset password are rate limited per IP (and per email where relevant).

Signs in with email and password and returns a Bearer token.

POST
Login
Public
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/login
Request Body
Field Type Rules Description
email string Required email User email address
password string Required User password
Example Request
{
    "email": "[email protected]",
    "password": "password"
}
Response (200)
{
    "success": true,
    "data": {
        "user": {
            "id": 1,
            "prename": "Ion",
            "name": "Popescu",
            "email": "[email protected]",
            "role": "admin"
        },
        "token": "1|laravel_sanctum_token_string...",
        "token_type": "Bearer"
    },
    "message": "Autentificare reu\u0219it\u0103"
}
Response (422)
{
    "message": "Creden\u021bialele furnizate sunt incorecte.",
    "errors": {
        "email": [
            "Creden\u021bialele furnizate sunt incorecte."
        ]
    }
}
Response (429)
{
    "success": false,
    "message": "Prea multe \u00eencerc\u0103ri. V\u0103 rug\u0103m s\u0103 \u00eencerca\u021bi din nou mai t\u00e2rziu."
}

Creates your account from an admin invitation. Registration is invite-only: use the token and email from the invitation link. The account gets the role chosen in the invitation.

POST
Register
Public
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/register
Request Body
Field Type Rules Description
token string Required Invitation token from the invitation email/link
name string Required max:255 Full name
email string Required email Email address the invitation was sent to
password string Required min:8|confirmed Password
password_confirmation string Required Confirm password
Example Request
{
    "token": "Xk3...64-character-token...9fQ",
    "name": "New User",
    "email": "[email protected]",
    "password": "password123",
    "password_confirmation": "password123"
}
Response (201)
{
    "success": true,
    "data": {
        "user": {
            "id": 2,
            "name": "New User",
            "email": "[email protected]",
            "role": "user"
        },
        "token": "2|laravel_sanctum_token...",
        "token_type": "Bearer"
    },
    "message": "\u00cenregistrare reu\u0219it\u0103"
}
Response (422)
{
    "message": "Invita\u021bia este invalid\u0103 sau a expirat.",
    "errors": {
        "token": [
            "Invita\u021bia este invalid\u0103 sau a expirat."
        ]
    }
}

Exchanges an API key (bought on /api-key) for a Bearer token. API-key consumers are never admins.

POST
API Key Login
Public
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/api-key
Request Body
Field Type Rules Description
api_key string Required Your API key (shown once when created)
Example Request
{
    "api_key": "pc_ab12cd34_0123abcd..."
}
Response (200)
{
    "success": true,
    "data": {
        "consumer": {
            "id": 1,
            "name": "My Integration",
            "plan": "standard"
        },
        "token": "1|laravel_sanctum_token_string...",
        "token_type": "Bearer"
    },
    "message": "Schimb de cheie API reu\u0219it"
}
Response (401)
{
    "success": false,
    "message": "Cheie API invalid\u0103."
}

Emails a password reset link when an account with that email exists. data.found tells whether one did.

POST
Forgot Password
Public
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/forgot-password
Request Body
Field Type Rules Description
email string Required email Account email
Example Request
{
    "email": "[email protected]"
}
Response (200)
{
    "success": true,
    "data": {
        "found": true
    },
    "message": "Un link de resetare a parolei a fost trimis la adresa dvs. de email."
}

Sets a new password using the token from the reset email.

POST
Reset Password
Public
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/reset-password
Request Body
Field Type Rules Description
token string Required Token from the reset link
email string Required email Account email
password string Required min:8|confirmed New password
password_confirmation string Required Confirm new password
Example Request
{
    "token": "abc123...",
    "email": "[email protected]",
    "password": "newpassword",
    "password_confirmation": "newpassword"
}
Response (200)
{
    "success": true,
    "message": "Parola a fost resetat\u0103 cu succes. Acum v\u0103 pute\u021bi autentifica cu noua parol\u0103."
}
Response (422)
{
    "message": "Acest token de resetare a parolei este invalid sau a expirat.",
    "errors": {
        "email": [
            "Acest token de resetare a parolei este invalid sau a expirat."
        ]
    }
}

Revokes the token used for this request.

POST
Logout
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/logout
Response (200)
{
    "success": true,
    "message": "Deconectare reu\u0219it\u0103"
}
Response (401)
{
    "message": "Neautentificat. V\u0103 rug\u0103m s\u0103 v\u0103 autentifica\u021bi."
}

Returns the signed-in user.

GET
Get Current User
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/me
Response (200)
{
    "success": true,
    "data": {
        "id": 1,
        "prename": "Ion",
        "name": "Popescu",
        "email": "[email protected]",
        "role": "admin"
    },
    "message": "Date utilizator preluate cu succes"
}
Response (401)
{
    "message": "Neautentificat. V\u0103 rug\u0103m s\u0103 v\u0103 autentifica\u021bi."
}

Changes your own first and last name. Email, password and role are changed by an admin via /users.

PUT
Update Current User
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/auth/me
Request Body
Field Type Rules Description
prename string max:255 First name
name string max:255 Last name
Example Request
{
    "prename": "Ion",
    "name": "Ionescu"
}
Response (200)
{
    "success": true,
    "data": {
        "id": 1,
        "prename": "Ion",
        "name": "Ionescu",
        "email": "[email protected]",
        "role": "admin"
    },
    "message": "Profil actualizat cu succes"
}
Response (401)
{
    "message": "Neautentificat. V\u0103 rug\u0103m s\u0103 v\u0103 autentifica\u021bi."
}

Users

Operators (technicians) and admins. Any signed-in user can list and view users; creating, updating and deleting is admin only (403 otherwise). Users with quotes or open schedules cannot be deleted (409).

Paginated list of users (yourself included), newest first.

GET
List Users
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/users
Parameters
Name Type Required Description
page integer Optional Page number
per_page integer Optional Items per page (default 15)
search string Optional Search by name or email
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 2,
                "prename": "Maria",
                "name": "Ionescu",
                "role": "user"
            }
        ],
        "per_page": 15,
        "total": 1,
        "last_page": 1
    },
    "message": "Utilizatori prelua\u021bi cu succes"
}
Response (401)
{
    "message": "Neautentificat. V\u0103 rug\u0103m s\u0103 v\u0103 autentifica\u021bi."
}

Creates a user directly (admins can also invite instead). Admin only.

POST
Create User
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/users
Request Body
Field Type Rules Description
prename string max:255 First name
name string Required max:255 Last name
email string Required email|unique:users Email address
password string Required min:8|confirmed Password
password_confirmation string Required Confirm password
role string in:user,moderator,admin Role (default user)
Example Request
{
    "prename": "Maria",
    "name": "Ionescu",
    "email": "[email protected]",
    "password": "secret123",
    "password_confirmation": "secret123"
}
Response (201)
{
    "success": true,
    "data": {
        "id": 3,
        "prename": "Maria",
        "name": "Ionescu",
        "email": "[email protected]",
        "role": "user"
    },
    "message": "Utilizator creat cu succes"
}
Response (403)
{
    "success": false,
    "message": "Acces interzis. Doar administratorii pot efectua aceast\u0103 ac\u021biune."
}
Response (422)
{
    "message": "Valoarea pentru email a fost deja folosit\u0103.",
    "errors": {
        "email": [
            "Valoarea pentru email a fost deja folosit\u0103."
        ]
    }
}

One user.

GET
Get User
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/users/{id}
Response (200)
{
    "success": true,
    "data": {
        "id": 2,
        "prename": "Maria",
        "name": "Ionescu",
        "email": "[email protected]",
        "role": "user"
    },
    "message": "Utilizator preluat cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Changes any of the sent fields. Admin only; the last remaining admin cannot be demoted (422).

PUT
Update User
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/users/{id}
Request Body
Field Type Rules Description
prename string max:255 First name
name string max:255 Last name
email string email|unique:users Email address
password string min:8|confirmed New password (send password_confirmation too)
role string in:user,moderator,admin Role
Example Request
{
    "role": "moderator"
}
Response (200)
{
    "success": true,
    "data": {
        "id": 2,
        "prename": "Maria",
        "name": "Ionescu",
        "email": "[email protected]",
        "role": "moderator"
    },
    "message": "Utilizator actualizat cu succes"
}
Response (403)
{
    "success": false,
    "message": "Acces interzis. Doar administratorii pot efectua aceast\u0103 ac\u021biune."
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (422)
{
    "success": false,
    "message": "Nu se poate retrograda ultimul administrator."
}

Deletes a user. Admin only; you cannot delete yourself (422), nor a user with quotes or assigned schedules (409). Their cancelled schedules are deleted with them.

DELETE
Delete User
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/users/{id}
Response (200)
{
    "success": true,
    "message": "Utilizator \u0219ters cu succes"
}
Response (403)
{
    "success": false,
    "message": "Acces interzis. Doar administratorii pot efectua aceast\u0103 ac\u021biune."
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (409)
{
    "success": false,
    "message": "Utilizatorul nu poate fi \u0219ters deoarece are oferte sau program\u0103ri asociate. Reasigna\u021bi-le \u00eenainte de \u0219tergere."
}

Invitations

Registration is invite-only. Admins invite an email address with a role; the invitee registers with the emailed token (POST /auth/register). Invitations expire after 7 days and work once. All endpoints are admin only (403 otherwise).

Shows invitations that have not been used or expired yet. Admin only.

GET
List Invitations
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/invitations
Response (200)
{
    "success": true,
    "data": [
        {
            "id": 1,
            "email": "[email protected]",
            "role": "user",
            "expires_at": "2026-10-10T10:00:00.000000Z",
            "invited_by": "Ion Popescu"
        }
    ],
    "message": "Invita\u021bii preluate cu succes"
}
Response (403)
{
    "success": false,
    "message": "Acces interzis. Doar administratorii pot efectua aceast\u0103 ac\u021biune."
}

Invites an email address to register and emails them a link. Replaces any pending invitation for the same address. The response includes the link too, in case the email does not arrive (mail_sent tells you, and mail_error gives the reason in Romanian when it is false). Admin only.

POST
Invite User
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/invitations
Request Body
Field Type Rules Description
email string Required email Address to invite (must not already have an account)
role string in:user,moderator,admin Role the new account will get (default user)
Example Request
{
    "email": "[email protected]",
    "role": "user"
}
Response (201)
{
    "success": true,
    "data": {
        "id": 1,
        "email": "[email protected]",
        "role": "user",
        "expires_at": "2026-10-10T10:00:00.000000Z",
        "invite_url": "https://app.example.com/register?token=...&email=new%40example.com",
        "mail_sent": true,
        "mail_error": null
    },
    "message": "Invita\u021bie creat\u0103 cu succes"
}
Response (422)
{
    "message": "Exist\u0103 deja un cont cu aceast\u0103 adres\u0103 de email.",
    "errors": {
        "email": [
            "Exist\u0103 deja un cont cu aceast\u0103 adres\u0103 de email."
        ]
    }
}

Cancels a pending invitation so its link stops working. Admin only.

DELETE
Revoke Invitation
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/invitations/{id}
Response (200)
{
    "success": true,
    "message": "Invita\u021bie revocat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Company Profile

The company details and stamp printed on PDFs. One shared profile; values not set fall back to the COMPANY_* environment variables.

Company details, with the stamp image as a base64 data URI when one is uploaded.

GET
Get Company Profile
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/profile
Response (200)
{
    "success": true,
    "data": {
        "name": "SC Exemplu DDD SRL",
        "cui": "RO12345678",
        "registration_number": "J40/123/2020",
        "email": "[email protected]",
        "phone": "0712345678",
        "website": "https://exemplu.ro",
        "iban": "RO49AAAA1B31007593840000",
        "bank_name": "Banca Exemplu",
        "address": "Str. Florilor 1, Bucure\u0219ti",
        "stamp_image": "stamps/abc123.png",
        "stamp_image_base64": "data:image/png;base64,iVBORw0KGgo..."
    },
    "message": "Profil companie preluat cu succes"
}

Changes the sent fields. Send multipart/form-data to upload the stamp (with _method=PUT when posting a form). Admin only.

PUT
Update Company Profile
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/profile
Request Body
Field Type Rules Description
name string max:255 Company name
cui string max:50 Tax code (CUI)
registration_number string max:50 Trade register number
email string email Contact email
phone string max:50 Phone
website string url Website
iban string max:50 IBAN
bank_name string max:255 Bank
address string max:500 Registered address
stamp_image file png,jpg,jpeg,webp|max:2MB Stamp image; replaces the current one
remove_stamp_image boolean Delete the current stamp
Example Request
{
    "phone": "0722000000"
}
Response (200)
{
    "success": true,
    "data": {
        "name": "SC Exemplu DDD SRL",
        "phone": "0722000000"
    },
    "message": "Profil companie actualizat cu succes"
}
Response (403)
{
    "success": false,
    "message": "Acces interzis. Doar administratorii pot modifica profilul companiei."
}

Client Categories

Categories every client belongs to (e.g. HORECA, Rezidențial).

All categories (not paginated).

GET
List Categories
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/client-categories
Response (200)
{
    "success": true,
    "data": [
        {
            "id": 1,
            "name": "HORECA",
            "created_at": "2026-01-03T09:00:00.000000Z",
            "updated_at": "2026-01-03T09:00:00.000000Z"
        }
    ],
    "message": "Categorii de clien\u021bi preluate cu succes"
}

Adds a category.

POST
Create Category
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/client-categories
Request Body
Field Type Rules Description
name string Required max:255|unique Category name
Example Request
{
    "name": "HORECA"
}
Response (201)
{
    "success": true,
    "data": {
        "id": 1,
        "name": "HORECA",
        "created_at": "2026-01-03T09:00:00.000000Z",
        "updated_at": "2026-01-03T09:00:00.000000Z"
    },
    "message": "Categorie de clien\u021bi creat\u0103 cu succes"
}
Response (422)
{
    "message": "Valoarea pentru name a fost deja folosit\u0103.",
    "errors": {
        "name": [
            "Valoarea pentru name a fost deja folosit\u0103."
        ]
    }
}

One category.

GET
Get Category
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/client-categories/{id}
Response (200)
{
    "success": true,
    "data": {
        "id": 1,
        "name": "HORECA",
        "created_at": "2026-01-03T09:00:00.000000Z",
        "updated_at": "2026-01-03T09:00:00.000000Z"
    },
    "message": "Categorie de clien\u021bi preluat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Renames a category.

PUT
Rename Category
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/client-categories/{id}
Request Body
Field Type Rules Description
name string Required max:255|unique Category name
Example Request
{
    "name": "Restaurante"
}
Response (200)
{
    "success": true,
    "data": {
        "id": 1,
        "name": "Restaurante"
    },
    "message": "Categorie de clien\u021bi actualizat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Deletes a category that has no clients (422 otherwise).

DELETE
Delete Category
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/client-categories/{id}
Response (200)
{
    "success": true,
    "message": "Categorie de clien\u021bi \u0219tears\u0103 cu succes"
}
Response (422)
{
    "success": false,
    "message": "Nu se poate \u0219terge categoria care are clien\u021bi asigna\u021bi."
}

Clients

Clients, their service addresses and contracted services. Saving a client keeps one upcoming "client_frequency" visit per address covering its enabled services (e.g. "deratizare,dezinsectie") that no other open schedule at that address already plans, at the smallest frequency among enabled services. The date is set when the visit is first planned or the smallest frequency changes (last completed visit + frequency, not before today, or today + frequency); other edits keep it. Visits of removed addresses are cancelled; completed and in-progress visits are never changed. Clients with quotes or completed/in-progress visits cannot be deleted (409).

Paginated list, newest first.

GET
List Clients
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/clients
Parameters
Name Type Required Description
page integer Optional Page number
per_page integer Optional Items per page (default 15)
search string Optional Search by name, email or tax code
category_id integer Optional Filter by category
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 5,
                "name": "Restaurant Luigi SRL",
                "tax_code": "RO123456",
                "contact_person": "Luigi Rossi",
                "addresses": "Str. Florilor 1, Bucure\u0219ti; Str. Lalelelor 2, Bucure\u0219ti",
                "phone_number": "0712345678",
                "service_deratizare": true,
                "service_dezinsectie": true,
                "service_dezinfectie": false
            }
        ],
        "per_page": 15,
        "total": 1,
        "last_page": 1
    },
    "message": "Clien\u021bi prelua\u021bi cu succes"
}
Response (401)
{
    "message": "Neautentificat. V\u0103 rug\u0103m s\u0103 v\u0103 autentifica\u021bi."
}

Adds a client and schedules its first visit per address when a service with a frequency is enabled.

POST
Create Client
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/clients
Request Body
Field Type Rules Description
name string Required max:255 Company or client name
tax_code string Required max:255 Tax code (CUI/CNP)
commercial_register_number string Required max:255 Trade register number
addresses array Required min:1 Service addresses; one schedule is kept per address
addresses.* string Required no ";" One address (stored joined with "; ", so it cannot contain ";")
phone_number string Required max:50 Phone
email string email|max:255 Email (nullable)
contact_person string Required max:255 Contact person
contract string max:255 Contract number and date as free text, e.g. "CTR-001 din 15.01.2026" (nullable); shown on the client's Proces Verbal PDFs
service_deratizare boolean Rodent control contracted
frequency_deratizare integer min:1|max:3650 Days between deratizare visits (nullable)
service_dezinsectie boolean Insect control contracted
frequency_dezinsectie integer min:1|max:3650 Days between dezinsectie visits (nullable)
service_dezinfectie boolean Disinfection contracted
frequency_dezinfectie integer min:1|max:3650 Days between dezinfectie visits (nullable)
client_category_id integer Required exists:client_categories,id Category
Example Request
{
    "name": "Restaurant Luigi SRL",
    "tax_code": "RO123456",
    "commercial_register_number": "J40/123/2020",
    "addresses": [
        "Str. Florilor 1, Bucure\u0219ti",
        "Str. Lalelelor 2, Bucure\u0219ti"
    ],
    "phone_number": "0712345678",
    "email": "[email protected]",
    "contact_person": "Luigi Rossi",
    "service_deratizare": true,
    "frequency_deratizare": 30,
    "client_category_id": 1
}
Response (201)
{
    "success": true,
    "data": {
        "id": 5,
        "name": "Restaurant Luigi SRL",
        "tax_code": "RO123456",
        "commercial_register_number": "J40/123/2020",
        "addresses": "Str. Florilor 1, Bucure\u0219ti; Str. Lalelelor 2, Bucure\u0219ti",
        "phone_number": "0712345678",
        "email": "[email protected]",
        "contact_person": "Luigi Rossi",
        "contract": "CTR-001 din 15.01.2026",
        "service_deratizare": true,
        "frequency_deratizare": 30,
        "service_dezinsectie": true,
        "frequency_dezinsectie": 90,
        "service_dezinfectie": false,
        "frequency_dezinfectie": null,
        "category": {
            "id": 1,
            "name": "HORECA"
        }
    },
    "message": "Client creat cu succes"
}
Response (422)
{
    "message": "O adres\u0103 nu poate con\u021bine caracterul \u201e;\u201d. Ad\u0103uga\u021bi fiecare adres\u0103 separat.",
    "errors": {
        "addresses.0": [
            "O adres\u0103 nu poate con\u021bine caracterul \u201e;\u201d. Ad\u0103uga\u021bi fiecare adres\u0103 separat."
        ]
    }
}

One client with its category.

GET
Get Client
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/clients/{id}
Response (200)
{
    "success": true,
    "data": {
        "id": 5,
        "name": "Restaurant Luigi SRL",
        "tax_code": "RO123456",
        "commercial_register_number": "J40/123/2020",
        "addresses": "Str. Florilor 1, Bucure\u0219ti; Str. Lalelelor 2, Bucure\u0219ti",
        "phone_number": "0712345678",
        "email": "[email protected]",
        "contact_person": "Luigi Rossi",
        "contract": "CTR-001 din 15.01.2026",
        "service_deratizare": true,
        "frequency_deratizare": 30,
        "service_dezinsectie": true,
        "frequency_dezinsectie": 90,
        "service_dezinfectie": false,
        "frequency_dezinfectie": null,
        "category": {
            "id": 1,
            "name": "HORECA"
        }
    },
    "message": "Client preluat cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Changes only the sent fields (required fields cannot be cleared) and re-syncs the frequency schedules.

PUT
Update Client
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/clients/{id}
Request Body
Field Type Rules Description
name string max:255 Company or client name
tax_code string max:255 Tax code (CUI/CNP)
commercial_register_number string max:255 Trade register number
addresses array min:1 Service addresses; one schedule is kept per address
addresses.* string Required no ";" One address (stored joined with "; ", so it cannot contain ";")
phone_number string max:50 Phone
email string email|max:255 Email (nullable)
contact_person string max:255 Contact person
contract string max:255 Contract number and date as free text, e.g. "CTR-001 din 15.01.2026" (nullable); shown on the client's Proces Verbal PDFs
service_deratizare boolean Rodent control contracted
frequency_deratizare integer min:1|max:3650 Days between deratizare visits (nullable)
service_dezinsectie boolean Insect control contracted
frequency_dezinsectie integer min:1|max:3650 Days between dezinsectie visits (nullable)
service_dezinfectie boolean Disinfection contracted
frequency_dezinfectie integer min:1|max:3650 Days between dezinfectie visits (nullable)
client_category_id integer exists:client_categories,id Category
Example Request
{
    "phone_number": "0722000000",
    "frequency_deratizare": 14
}
Response (200)
{
    "success": true,
    "data": {
        "id": 5,
        "name": "Restaurant Luigi SRL",
        "tax_code": "RO123456",
        "commercial_register_number": "J40/123/2020",
        "addresses": "Str. Florilor 1, Bucure\u0219ti; Str. Lalelelor 2, Bucure\u0219ti",
        "phone_number": "0722000000",
        "email": "[email protected]",
        "contact_person": "Luigi Rossi",
        "contract": "CTR-001 din 15.01.2026",
        "service_deratizare": true,
        "frequency_deratizare": 14,
        "service_dezinsectie": true,
        "frequency_dezinsectie": 90,
        "service_dezinfectie": false,
        "frequency_dezinfectie": null,
        "category": {
            "id": 1,
            "name": "HORECA"
        }
    },
    "message": "Client actualizat cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (422)
{
    "message": "C\u00e2mpul frequency deratizare nu poate fi mai mare de 3650.",
    "errors": {
        "frequency_deratizare": [
            "C\u00e2mpul frequency deratizare nu poate fi mai mare de 3650."
        ]
    }
}

Deletes a client and its planned/cancelled schedules. Refused (409) when it has quotes (even deleted ones) or completed/in-progress visits.

DELETE
Delete Client
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/clients/{id}
Response (200)
{
    "success": true,
    "message": "Client \u0219ters cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (409)
{
    "success": false,
    "message": "Clientul nu poate fi \u0219ters deoarece are oferte (procese verbale) sau program\u0103ri finalizate/\u00een desf\u0103\u0219urare."
}

Paginated schedules of one client, newest first.

GET
Client Schedules
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/clients/{id}/schedules
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 12,
                "date": "2026-11-03",
                "client_name_prename": "Restaurant Luigi SRL",
                "client_phone_number": "0712345678",
                "type_of_intervention": "deratizare",
                "operator": "Ion Popescu"
            }
        ],
        "per_page": 15,
        "total": 1,
        "last_page": 1
    },
    "message": "Program\u0103ri client preluate cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Paginated quotes (Proces Verbal) of one client, newest first.

GET
Client Quotes
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/clients/{id}/quotes
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 45,
                "date": "2026-10-01",
                "time": "10:00",
                "client": {
                    "id": 5,
                    "name": "Restaurant Luigi SRL",
                    "phone_number": "0712345678"
                },
                "user": {
                    "id": 2,
                    "name": "Ion Popescu"
                },
                "address": "Str. Florilor 1, Bucure\u0219ti"
            }
        ],
        "per_page": 15,
        "total": 1,
        "last_page": 1
    },
    "message": "Oferte client preluate cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Materials

Materials and their stock. A material is a header (name, procedure, unit); stock lives on its variants (batches): quantity containers of capacity mL/g each, so stock = quantity × capacity. Every stock change writes a movement (type in/out) to the material ledger; quotes consume stock through their material lines. Materials and variants are soft-deleted.

Paginated list, newest first, with the nearest variant expiration date.

GET
List Materials
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials
Parameters
Name Type Required Description
page integer Optional Page number
per_page integer Optional Items per page (default 15)
search string Optional Search by name or variant lot
procedure string Optional Filter by procedure
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 3,
                "name": "Deltamethrin 2.5",
                "procedure": "dezinsectie",
                "unit_measure": "mL",
                "closest_expiration_date": "2027-01-10",
                "variants_count": 1
            }
        ],
        "per_page": 15,
        "total": 1,
        "last_page": 1
    },
    "message": "Materiale preluate cu succes"
}

Creates the material with its first variant and logs the initial "in" movement.

POST
Create Material
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials
Request Body
Field Type Rules Description
name string Required max:255|unique (deleted materials included) Material name
procedure string Required max:255 deratizare / dezinsectie / dezinfectie
unit_measure string Required max:50 Unit of capacity (the app sends mL, g or buc)
contact_time string Required max:255 Contact time
aviz string Approval (aviz) number
quantity number Required min:1|max:10000 Number of containers (may be fractional)
capacity integer Required min:1|max:100000 Size of one container in the material unit (mL/g/buc); unique per material
lot string Required max:255 Lot number
invoice string Required max:255 Invoice number
date_of_acquisition date Required before expiration_date Acquisition date
expiration_date date Required after date_of_acquisition Expiration date
Example Request
{
    "name": "Deltamethrin 2.5",
    "procedure": "dezinsectie",
    "unit_measure": "mL",
    "contact_time": "30 minute",
    "aviz": "Aviz 123/2026",
    "lot": "LOT-001",
    "invoice": "FCT-001",
    "capacity": 1000,
    "quantity": 3,
    "date_of_acquisition": "2026-01-10",
    "expiration_date": "2027-01-10"
}
Response (201)
{
    "success": true,
    "data": {
        "id": 3,
        "name": "Deltamethrin 2.5",
        "procedure": "dezinsectie",
        "aviz": "Aviz 123/2026",
        "contact_time": "30 minute",
        "unit_measure": "mL",
        "variants": [
            {
                "variant_id": 7,
                "capacity": 1000,
                "quantity": "3.00",
                "stock": 3000,
                "lot": "LOT-001",
                "invoice": "FCT-001",
                "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
                "expiration_date": "2027-01-10T00:00:00.000000Z"
            }
        ]
    },
    "message": "Material creat cu succes"
}
Response (422)
{
    "message": "C\u00e2mpul expiration date trebuie s\u0103 fie o dat\u0103 dup\u0103 date of acquisition.",
    "errors": {
        "expiration_date": [
            "C\u00e2mpul expiration date trebuie s\u0103 fie o dat\u0103 dup\u0103 date of acquisition."
        ]
    }
}

One material with its variants.

GET
Get Material
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}
Response (200)
{
    "success": true,
    "data": {
        "id": 3,
        "name": "Deltamethrin 2.5",
        "procedure": "dezinsectie",
        "aviz": "Aviz 123/2026",
        "contact_time": "30 minute",
        "unit_measure": "mL",
        "variants": [
            {
                "variant_id": 7,
                "capacity": 1000,
                "quantity": "3.00",
                "stock": 3000,
                "lot": "LOT-001",
                "invoice": "FCT-001",
                "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
                "expiration_date": "2027-01-10T00:00:00.000000Z"
            }
        ]
    },
    "message": "Material preluat cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Changes the header fields. Stock and batch details are changed through the variant endpoints.

PUT
Update Material
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}
Request Body
Field Type Rules Description
name string max:255|unique Material name
procedure string max:255 Procedure
unit_measure string max:50 Unit
contact_time string max:255 Contact time
aviz string Approval number (nullable)
Example Request
{
    "contact_time": "1 or\u0103"
}
Response (200)
{
    "success": true,
    "data": {
        "id": 3,
        "name": "Deltamethrin 2.5",
        "procedure": "dezinsectie",
        "aviz": "Aviz 123/2026",
        "contact_time": "1 or\u0103",
        "unit_measure": "mL",
        "variants": [
            {
                "variant_id": 7,
                "capacity": 1000,
                "quantity": "3.00",
                "stock": 3000,
                "lot": "LOT-001",
                "invoice": "FCT-001",
                "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
                "expiration_date": "2027-01-10T00:00:00.000000Z"
            }
        ]
    },
    "message": "Material actualizat cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (422)
{
    "message": "Valoarea pentru name a fost deja folosit\u0103.",
    "errors": {
        "name": [
            "Valoarea pentru name a fost deja folosit\u0103."
        ]
    }
}

Soft-deletes the material. Existing quotes keep showing it; new quote lines cannot use it.

DELETE
Delete Material
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}
Response (200)
{
    "success": true,
    "message": "Material \u0219ters cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Variants expiring between now and now + days, soonest first, with their material.

GET
Expiring Variants
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/expiring
Parameters
Name Type Required Description
days integer Optional Window in days (default 30)
Response (200)
{
    "success": true,
    "data": [
        {
            "variant_id": 7,
            "capacity": 1000,
            "quantity": "3.00",
            "stock": 3000,
            "lot": "LOT-001",
            "invoice": "FCT-001",
            "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
            "expiration_date": "2026-10-20T00:00:00.000000Z",
            "material": {
                "id": 3,
                "name": "Deltamethrin 2.5"
            }
        }
    ],
    "message": "Materiale apropiat de expirare preluate cu succes"
}

Adds a batch to the material and logs its "in" movement. At most 6 variants per material; several batches may share a capacity.

POST
Add Variant
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/variants
Request Body
Field Type Rules Description
capacity integer Required min:1|max:100000 Size of one container in the material unit (mL/g/buc); unique per material
lot string Required max:255 Lot number
invoice string Required max:255 Invoice number
date_of_acquisition date Required before expiration_date Acquisition date
expiration_date date Required after date_of_acquisition Expiration date
quantity number Required min:1|max:10000 Number of containers
Example Request
{
    "capacity": 500,
    "lot": "LOT-002",
    "invoice": "FCT-002",
    "quantity": 4,
    "date_of_acquisition": "2026-02-01",
    "expiration_date": "2027-02-01"
}
Response (201)
{
    "success": true,
    "data": {
        "variant_id": 8,
        "capacity": 500,
        "quantity": "4.00",
        "stock": 2000,
        "lot": "LOT-001",
        "invoice": "FCT-001",
        "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
        "expiration_date": "2027-01-10T00:00:00.000000Z"
    },
    "message": "Variant\u0103 ad\u0103ugat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (422)
{
    "success": false,
    "message": "Eroare de validare",
    "errors": {
        "variants": "Un material nu poate avea mai mult de 6 variante."
    }
}

Edits batch details. Use quantity_add (positive or negative containers) to correct stock; it is logged as a movement. Changing capacity keeps the container count and logs the volume difference. A date sent alone is checked against the stored other date.

PUT
Update Variant
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/variants/{variantId}
Request Body
Field Type Rules Description
capacity integer min:1|max:100000 Size of one container in the material unit (mL/g/buc); unique per material
lot string max:255 Lot number
invoice string max:255 Invoice number
date_of_acquisition date before expiration_date Acquisition date
expiration_date date after date_of_acquisition Expiration date
quantity_add number max:10000 Containers to add (negative to remove); cannot take quantity below 0
Example Request
{
    "lot": "LOT-001-B",
    "quantity_add": -0.5
}
Response (200)
{
    "success": true,
    "data": {
        "variant_id": 7,
        "capacity": 1000,
        "quantity": "2.50",
        "stock": 2500,
        "lot": "LOT-001-B",
        "invoice": "FCT-001",
        "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
        "expiration_date": "2027-01-10T00:00:00.000000Z"
    },
    "message": "Variant\u0103 actualizat\u0103 cu succes"
}
Response (404)
{
    "success": false,
    "message": "Neg\u0103sit",
    "error": "Varianta nu apar\u021bine acestui material."
}
Response (422)
{
    "success": false,
    "message": "Eroare de validare",
    "errors": {
        "quantity_add": "Nu se poate reduce cantitatea sub zero. Cantitate curent\u0103: 2.00, modificare solicitat\u0103: -5"
    }
}

Soft-deletes a variant. The last variant of a material cannot be deleted (409).

DELETE
Delete Variant
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/variants/{variantId}
Response (200)
{
    "success": true,
    "message": "Variant\u0103 \u0219tears\u0103 cu succes"
}
Response (409)
{
    "success": false,
    "message": "Conflict",
    "error": "Un material trebuie s\u0103 aib\u0103 cel pu\u021bin o variant\u0103."
}

Adds one container to the variant and logs an "in" movement of one capacity.

POST
Add One Container
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/variants/{variantId}/increment
Response (200)
{
    "success": true,
    "data": {
        "variant_id": 7,
        "capacity": 1000,
        "quantity": "4.00",
        "stock": 4000,
        "lot": "LOT-001",
        "invoice": "FCT-001",
        "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
        "expiration_date": "2027-01-10T00:00:00.000000Z"
    },
    "message": "Stoc incrementat cu succes"
}

Takes an amount (in mL/g) out of the variant outside any quote and logs an "out" movement.

POST
Consume Stock
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/variants/{variantId}/consume
Request Body
Field Type Rules Description
amount number Required min:0.01|≤ available stock Amount in the material unit
Example Request
{
    "amount": 250
}
Response (200)
{
    "success": true,
    "data": {
        "variant_id": 7,
        "capacity": 1000,
        "quantity": "2.75",
        "stock": 2750,
        "lot": "LOT-001",
        "invoice": "FCT-001",
        "date_of_acquisition": "2026-01-10T00:00:00.000000Z",
        "expiration_date": "2027-01-10T00:00:00.000000Z"
    },
    "message": "Stoc consumat cu succes"
}
Response (422)
{
    "success": false,
    "message": "Eroare de stoc",
    "errors": {
        "amount": "Nu se poate consuma mai mult dec\u00e2t stocul disponibil. Disponibil: 3000 mL"
    }
}

Records a manual in/out movement on one of the material's variants and adjusts its quantity by stock ÷ capacity.

POST
Record Movement
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/movements
Request Body
Field Type Rules Description
type string Required in:in,out Direction
date date Required Movement date
stock integer Required min:1|max:1000000000 Amount in the material unit; "out" cannot exceed the variant stock
variant_id integer Required variant of this material, not deleted Variant
capacity integer min:1|max:100000 Container size to convert with (default: the variant capacity)
invoice string max:255 Invoice
lot string max:255 Lot
comments string Comments
signature string max:255 Signature
Example Request
{
    "type": "out",
    "date": "2026-10-01",
    "stock": 500,
    "variant_id": 7,
    "comments": "Pierdere"
}
Response (201)
{
    "success": true,
    "data": {
        "id": 30,
        "type": "out",
        "date": "2026-10-01",
        "stock": 500,
        "variant_id": 7,
        "capacity": 1000,
        "unit_measure": "mL"
    },
    "message": "Mi\u0219care \u00eenregistrat\u0103 \u0219i stoc actualizat cu succes"
}
Response (422)
{
    "success": false,
    "message": "Eroare de stoc",
    "errors": {
        "stock": "Stoc insuficient \u00een varianta selectat\u0103."
    }
}

Downloads the material ledger (all movements with running stock) as PDF.

GET
Export Ledger PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/export-pdf
Parameters
Name Type Required Description
date_from string Optional Only movements on or after this date; earlier movements become the opening stock
date_to string Optional Only movements on or before this date
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"3-Deltamethrin-2-5.pdf\""
}

Downloads the material ledger as CSV.

GET
Export Ledger CSV
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/{id}/export-csv
Parameters
Name Type Required Description
date_from string Optional Only movements on or after this date; earlier movements become the opening stock
date_to string Optional Only movements on or before this date
Response (200)
{
    "Content-Type": "text/csv",
    "Content-Disposition": "attachment; filename=\"3-Deltamethrin-2-5.csv\""
}

Downloads the ledgers of several materials as a ZIP of PDFs or CSVs.

POST
Export Ledgers (ZIP)
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/materials/export-bulk
Request Body
Field Type Rules Description
material_ids array Required exists:materials,id Materials to export
format string Required in:pdf,csv File format inside the ZIP
date_from string date_format:d-m-Y Ledger period start
date_to string date_format:d-m-Y Ledger period end
Example Request
{
    "material_ids": [
        3,
        4
    ],
    "format": "pdf"
}
Response (200)
{
    "Content-Type": "application/zip",
    "Content-Disposition": "attachment; filename=\"Export_Materiale_2026-10-03_12-00-00.zip\""
}

Schedules

Planned visits. Schedules with source "client_frequency" are maintained automatically from the client's service frequencies; saving a quote replaces open schedules for its address and services with the next visit. Statuses: scheduled, in_progress, completed, cancelled.

Paginated list, latest date first.

GET
List Schedules
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules
Parameters
Name Type Required Description
page integer Optional Page number
per_page integer Optional Items per page (default 15)
status string Optional Filter by status
client_id integer Optional Filter by client
user_id integer Optional Filter by operator
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 12,
                "date": "2026-11-03",
                "client_name_prename": "Restaurant Luigi SRL",
                "client_phone_number": "0712345678",
                "type_of_intervention": "deratizare",
                "operator": "Ion Popescu",
                "address_short": "Str. Florilor 1, Bucure\u0219ti"
            }
        ],
        "per_page": 15,
        "total": 1,
        "last_page": 1
    },
    "message": "Program\u0103ri preluate cu succes"
}

Plans a visit. Open (scheduled/in progress) schedules of the same client at the same address that share a whole intervention type are replaced (case, diacritics and address abbreviations are ignored when comparing).

POST
Create Schedule
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules
Request Body
Field Type Rules Description
type_of_intervention string Required not only separators Free text; several services comma separated, e.g. "deratizare,dezinfectie"
date date Required Visit date
time time Required H:i Visit time
client_id integer Required exists:clients,id Client
user_id integer Required exists:users,id Assigned operator
address string Required Visit address
phone_number string Required max:50 Contact phone
contact_person string Required max:255 Contact person
comments string Notes (nullable)
status string in:scheduled,in_progress,completed,cancelled Status (default scheduled)
Example Request
{
    "type_of_intervention": "deratizare",
    "date": "2026-11-03",
    "time": "09:30",
    "client_id": 5,
    "user_id": 2,
    "address": "Str. Florilor 1, Bucure\u0219ti",
    "phone_number": "0712345678",
    "contact_person": "Luigi Rossi",
    "comments": "Suna\u021bi \u00eenainte"
}
Response (201)
{
    "success": true,
    "data": {
        "id": 12,
        "type_of_intervention": "deratizare",
        "date": "2026-11-03T00:00:00.000000Z",
        "time": "09:30",
        "client_id": 5,
        "user_id": 2,
        "address": "Str. Florilor 1, Bucure\u0219ti",
        "comments": "Suna\u021bi \u00eenainte",
        "phone_number": "0712345678",
        "contact_person": "Luigi Rossi",
        "status": "scheduled",
        "source": null,
        "client": {
            "id": 5,
            "name": "Restaurant Luigi SRL"
        },
        "user": {
            "id": 2,
            "prename": "Ion",
            "name": "Popescu"
        }
    },
    "message": "Programare creat\u0103 cu succes"
}
Response (422)
{
    "message": "C\u00e2mpul time trebuie s\u0103 corespund\u0103 formatului H:i.",
    "errors": {
        "time": [
            "C\u00e2mpul time trebuie s\u0103 corespund\u0103 formatului H:i."
        ]
    }
}

One visit with the client's enabled services, their frequency and the date of the last quote per service.

GET
Get Schedule
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules/{id}
Response (200)
{
    "success": true,
    "data": {
        "id": 12,
        "date": "2026-11-03",
        "time": "09:30",
        "contact_person": "Luigi Rossi",
        "client_id": 5,
        "client_name": "Restaurant Luigi SRL",
        "operator_id": 2,
        "operator_name": "Ion Popescu",
        "client_address": "Str. Florilor 1, Bucure\u0219ti",
        "client_phone_number": "0712345678",
        "observations": "Suna\u021bi \u00eenainte",
        "intervention_type": "Deratizare",
        "last_quote": [
            {
                "procedura": "Deratizare",
                "data_ultimului_pv": "2026-10-01",
                "frecventa": "lunar",
                "valoare_frecventa": 30
            }
        ]
    },
    "message": "Programare preluat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Changes only the sent fields; required fields cannot be cleared. The source cannot be changed.

PUT
Update Schedule
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules/{id}
Request Body
Field Type Rules Description
type_of_intervention string not only separators Free text; several services comma separated, e.g. "deratizare,dezinfectie"
date date Visit date
time time H:i Visit time
client_id integer exists:clients,id Client
user_id integer exists:users,id Assigned operator
address string Visit address
phone_number string max:50 Contact phone
contact_person string max:255 Contact person
comments string Notes (nullable)
status string in:scheduled,in_progress,completed,cancelled Status (default scheduled)
Example Request
{
    "date": "2026-11-05",
    "time": "14:00"
}
Response (200)
{
    "success": true,
    "data": {
        "id": 12,
        "type_of_intervention": "deratizare",
        "date": "2026-11-05T00:00:00.000000Z",
        "time": "14:00",
        "client_id": 5,
        "user_id": 2,
        "address": "Str. Florilor 1, Bucure\u0219ti",
        "comments": "Suna\u021bi \u00eenainte",
        "phone_number": "0712345678",
        "contact_person": "Luigi Rossi",
        "status": "scheduled",
        "source": null,
        "client": {
            "id": 5,
            "name": "Restaurant Luigi SRL"
        },
        "user": {
            "id": 2,
            "prename": "Ion",
            "name": "Popescu"
        }
    },
    "message": "Programare actualizat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (422)
{
    "message": "C\u00e2mpul date trebuie s\u0103 corespund\u0103 formatului Y-m-d.",
    "errors": {
        "date": [
            "C\u00e2mpul date trebuie s\u0103 corespund\u0103 formatului Y-m-d."
        ]
    }
}

Deletes a visit.

DELETE
Delete Schedule
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules/{id}
Response (200)
{
    "success": true,
    "message": "Programare \u0219tears\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Changes only the status.

PATCH
Update Status
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules/{id}/status
Request Body
Field Type Rules Description
status string Required in:scheduled,in_progress,completed,cancelled New status
Example Request
{
    "status": "completed"
}
Response (200)
{
    "success": true,
    "data": {
        "id": 12,
        "type_of_intervention": "deratizare",
        "date": "2026-11-03T00:00:00.000000Z",
        "time": "09:30",
        "client_id": 5,
        "user_id": 2,
        "address": "Str. Florilor 1, Bucure\u0219ti",
        "comments": "Suna\u021bi \u00eenainte",
        "phone_number": "0712345678",
        "contact_person": "Luigi Rossi",
        "status": "completed",
        "source": null,
        "client": {
            "id": 5,
            "name": "Restaurant Luigi SRL"
        },
        "user": {
            "id": 2,
            "prename": "Ion",
            "name": "Popescu"
        }
    },
    "message": "Status programare actualizat cu succes"
}
Response (422)
{
    "message": "Valoarea selectat\u0103 pentru status este invalid\u0103.",
    "errors": {
        "status": [
            "Valoarea selectat\u0103 pentru status este invalid\u0103."
        ]
    }
}

Schedules between two dates, grouped by day.

GET
Calendar
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules/calendar
Parameters
Name Type Required Description
start_date date Required First day
end_date date Required Last day (on or after start_date)
Response (200)
{
    "success": true,
    "data": {
        "2026-11-03": [
            {
                "id": 12,
                "type_of_intervention": "deratizare",
                "date": "2026-11-03T00:00:00.000000Z",
                "time": "09:30",
                "client_id": 5,
                "user_id": 2,
                "address": "Str. Florilor 1, Bucure\u0219ti",
                "comments": "Suna\u021bi \u00eenainte",
                "phone_number": "0712345678",
                "contact_person": "Luigi Rossi",
                "status": "scheduled",
                "source": null,
                "client": {
                    "id": 5,
                    "name": "Restaurant Luigi SRL"
                },
                "user": {
                    "id": 2,
                    "prename": "Ion",
                    "name": "Popescu"
                }
            }
        ]
    },
    "message": "Program\u0103ri calendar preluate cu succes"
}
Response (422)
{
    "message": "C\u00e2mpul start date este obligatoriu.",
    "errors": {
        "start_date": [
            "C\u00e2mpul start date este obligatoriu."
        ]
    }
}

Downloads the selected schedules as a landscape PDF list, ordered by date and time.

POST
Export Schedules PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules/export-pdf
Request Body
Field Type Rules Description
schedule_ids array Required min:1|exists:schedules,id Schedules to export
Example Request
{
    "schedule_ids": [
        12,
        13
    ]
}
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"Export_Programari_2026-10-03_12-00-00.pdf\""
}
Response (422)
{
    "message": "C\u00e2mpul schedule ids este obligatoriu.",
    "errors": {
        "schedule_ids": [
            "C\u00e2mpul schedule ids este obligatoriu."
        ]
    }
}

Downloads the selected schedules as CSV (UTF-8 with BOM, for Excel).

POST
Export Schedules CSV
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/schedules/export-csv
Request Body
Field Type Rules Description
schedule_ids array Required min:1|exists:schedules,id Schedules to export
Example Request
{
    "schedule_ids": [
        12,
        13
    ]
}
Response (200)
{
    "Content-Type": "text/csv",
    "Content-Disposition": "attachment; filename=\"Export_Programari_2026-10-03_12-00-00.csv\""
}

Quotes (Proces Verbal)

Intervention reports, exported as Proces Verbal PDFs. Numbers (QT-YYYY-NNNNN) and the initial status (pending) are set by the server. Saving a quote schedules the next visit at date + the smallest recall days of its services (or the client's frequency) and returns it as scheduled_date. Stock changes from material lines are all-or-nothing: insufficient stock rejects the whole save (422). Statuses: pending, approved, rejected, completed.

Paginated list, newest first.

GET
List Quotes
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes
Parameters
Name Type Required Description
page integer Optional Page number
per_page integer Optional Items per page (default 15)
search string Optional Search by quote number or client name
status string Optional Filter by status
client_id integer Optional Filter by client
user_id integer Optional Filter by operator
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 45,
                "quote_number": "QT-2026-00045",
                "date": "2026-10-01",
                "time": "10:00",
                "client": {
                    "id": 5,
                    "name": "Restaurant Luigi SRL",
                    "phone_number": "0712345678"
                },
                "user": {
                    "id": 2,
                    "name": "Ion Popescu"
                },
                "address": "Str. Florilor 1, Bucure\u0219ti",
                "type_of_intervention": "dezinsectie"
            }
        ],
        "per_page": 15,
        "total": 1,
        "last_page": 1
    },
    "message": "Oferte preluate cu succes"
}

Creates the quote, its material lines (consuming stock) and the next visit.

POST
Create Quote
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes
Request Body
Field Type Rules Description
date date Required Intervention date
time time Required H:i Intervention time
client_id integer Required exists:clients,id Client
address string Required max:255 Service address
type_of_intervention string Required Services performed, comma separated, e.g. "deratizare,dezinsectie"
user_id integer Required exists:users,id Operator
representative string Required max:255 Client representative
spaces string Required Treated spaces
surface number Required min:0|max:999999.99 Treated surface
surface_unit_measure string max:20 Surface unit (the app sends mp, mc or km); m² when empty
deratizare_recall_days integer min:0|max:3650 Days until the next deratizare visit (0/empty: client frequency)
deratizare_warranty_months integer min:0|max:120 Warranty months
dezinsectie_recall_days integer min:0|max:3650 Days until the next dezinsectie visit
dezinsectie_warranty_months integer min:0|max:120 Warranty months
dezinfectie_recall_days integer min:0|max:3650 Days until the next dezinfectie visit
dezinfectie_warranty_months integer min:0|max:120 Warranty months
comments string Observations (nullable)
apply_stamp_pdf boolean Print the company stamp on the PDF
materials array Material lines; each consumes stock from its variant
materials.*.material_id integer Required exists, not deleted Material
materials.*.variant_id integer Required variant of that material, not deleted Batch the stock is taken from
materials.*.category string Required in:deratizare,dezinsectie,dezinfectie Service; one line per material and category
materials.*.capacity_consumed number Required min:0.01|max:99999999.99|≤ variant stock Amount used, in mL/g
materials.*.unit_measure string Required max:50 Unit
materials.*.dilution string max:100 Dilution, e.g. 1:100
materials.*.application_method string max:255 Application method
Example Request
{
    "date": "2026-10-01",
    "time": "10:00",
    "client_id": 5,
    "address": "Str. Florilor 1, Bucure\u0219ti",
    "type_of_intervention": "dezinsectie",
    "user_id": 2,
    "representative": "Luigi Rossi",
    "spaces": "Buc\u0103t\u0103rie, depozit",
    "surface": 150,
    "dezinsectie_recall_days": 14,
    "dezinsectie_warranty_months": 3,
    "apply_stamp_pdf": true,
    "materials": [
        {
            "material_id": 3,
            "variant_id": 7,
            "category": "dezinsectie",
            "capacity_consumed": 250,
            "unit_measure": "mL",
            "dilution": "1:100",
            "application_method": "Pulverizare"
        }
    ]
}
Response (201)
{
    "success": true,
    "data": {
        "id": 45,
        "quote_number": "QT-2026-00045",
        "status": "pending",
        "date": "2026-10-01T00:00:00.000000Z",
        "scheduled_date": "2026-10-15"
    },
    "message": "Ofert\u0103 creat\u0103 cu succes"
}
Response (422)
{
    "success": false,
    "message": "Eroare de stoc",
    "errors": {
        "materials": "Stoc insuficient pentru materialul: Deltamethrin 2.5 (Lot variant\u0103: LOT-001). Necesar: 5000, Disponibil: 3000"
    }
}

One quote with client details and material lines.

GET
Get Quote
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/{id}
Response (200)
{
    "success": true,
    "data": {
        "id": 45,
        "quote_number": "QT-2026-00045",
        "date": "2026-10-01",
        "time": "10:00",
        "client_id": 5,
        "client_name": "Restaurant Luigi SRL",
        "client_cui": "RO123456",
        "client_address": "Str. Florilor 1, Bucure\u0219ti",
        "client_phone_number": "0712345678",
        "client_contract": "CTR-001 din 15.01.2026",
        "representative": "Luigi Rossi",
        "type_of_intervention": "dezinsectie",
        "spaces": "Buc\u0103t\u0103rie, depozit",
        "surface": 150,
        "surface_unit_measure": "m\u00b2",
        "dezinsectie_recall_days": 14,
        "dezinsectie_warranty_months": 3,
        "operator_name": "Ion Popescu",
        "observations": null,
        "apply_stamp": true,
        "status": "pending",
        "materials": [
            {
                "material_id": 3,
                "variant_id": 7,
                "category": "dezinsectie",
                "capacity_consumed": 250,
                "unit_measure": "mL",
                "dilution": "1:100",
                "application_method": "Pulverizare",
                "name": "Deltamethrin 2.5",
                "capacity": 1000
            }
        ]
    },
    "message": "Ofert\u0103 preluat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Changes only the sent fields (required fields cannot be cleared; number and status cannot be changed here). Lines whose variant or amount changed have their stock movement redone; lines whose material/variant was since deleted stay editable if unchanged.

PUT
Update Quote
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/{id}
Request Body
Field Type Rules Description
date date Intervention date
time time H:i Intervention time
client_id integer exists:clients,id Client
address string max:255 Service address
type_of_intervention string Services performed, comma separated, e.g. "deratizare,dezinsectie"
user_id integer exists:users,id Operator
representative string max:255 Client representative
spaces string Treated spaces
surface number min:0|max:999999.99 Treated surface
surface_unit_measure string max:20 Surface unit (the app sends mp, mc or km); m² when empty
deratizare_recall_days integer min:0|max:3650 Days until the next deratizare visit (0/empty: client frequency)
deratizare_warranty_months integer min:0|max:120 Warranty months
dezinsectie_recall_days integer min:0|max:3650 Days until the next dezinsectie visit
dezinsectie_warranty_months integer min:0|max:120 Warranty months
dezinfectie_recall_days integer min:0|max:3650 Days until the next dezinfectie visit
dezinfectie_warranty_months integer min:0|max:120 Warranty months
comments string Observations (nullable)
apply_stamp_pdf boolean Print the company stamp on the PDF
materials array When sent, the complete list of lines: lines left out are removed and their stock returned
materials.*.id integer a line of this quote Existing line to keep/edit; omit for a new line
materials.*.material_id integer Required exists, not deleted Material
materials.*.variant_id integer Required variant of that material, not deleted Batch the stock is taken from
materials.*.category string Required in:deratizare,dezinsectie,dezinfectie Service; one line per material and category
materials.*.capacity_consumed number Required min:0.01|max:99999999.99|≤ variant stock Amount used, in mL/g
materials.*.unit_measure string Required max:50 Unit
materials.*.dilution string max:100 Dilution, e.g. 1:100
materials.*.application_method string max:255 Application method
Example Request
{
    "comments": "Revenire peste 14 zile",
    "materials": [
        {
            "id": 90,
            "material_id": 3,
            "variant_id": 7,
            "category": "dezinsectie",
            "capacity_consumed": 300,
            "unit_measure": "mL",
            "dilution": "1:100",
            "application_method": "Pulverizare"
        }
    ]
}
Response (200)
{
    "success": true,
    "data": {
        "id": 45,
        "comments": "Revenire peste 14 zile",
        "scheduled_date": "2026-10-15"
    },
    "message": "Ofert\u0103 actualizat\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}
Response (422)
{
    "message": "Valoarea selectat\u0103 pentru materials.0.id este invalid\u0103.",
    "errors": {
        "materials.0.id": [
            "Valoarea selectat\u0103 pentru materials.0.id este invalid\u0103."
        ]
    }
}

Soft-deletes the quote, returns the stock its lines used and removes their lines and movements. Its number is never reused.

DELETE
Delete Quote
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/{id}
Response (200)
{
    "success": true,
    "message": "Ofert\u0103 \u0219tears\u0103 cu succes"
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Changes only the status.

PATCH
Update Status
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/{id}/status
Request Body
Field Type Rules Description
status string Required in:pending,approved,rejected,completed New status
Example Request
{
    "status": "approved"
}
Response (200)
{
    "success": true,
    "data": {
        "id": 45,
        "status": "approved"
    },
    "message": "Status ofert\u0103 actualizat cu succes"
}
Response (422)
{
    "message": "Valoarea selectat\u0103 pentru status este invalid\u0103.",
    "errors": {
        "status": [
            "Valoarea selectat\u0103 pentru status este invalid\u0103."
        ]
    }
}

Adds one material line to an existing quote and consumes its stock.

POST
Add Material Line
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/{id}/materials
Request Body
Field Type Rules Description
material_id integer Required exists, not deleted Material
variant_id integer Required variant of that material, not deleted Batch the stock is taken from
category string Required in:deratizare,dezinsectie,dezinfectie Service; one line per material and category
capacity_consumed number Required min:0.01|max:99999999.99|≤ variant stock Amount used, in mL/g
unit_measure string Required max:50 Unit
dilution string max:100 Dilution, e.g. 1:100
application_method string max:255 Application method
Example Request
{
    "material_id": 3,
    "variant_id": 7,
    "category": "dezinsectie",
    "capacity_consumed": 250,
    "unit_measure": "mL",
    "dilution": "1:100",
    "application_method": "Pulverizare"
}
Response (201)
{
    "success": true,
    "data": {
        "id": 91,
        "material_id": 3,
        "variant_id": 7,
        "category": "dezinsectie",
        "capacity_consumed": 250,
        "unit_measure": "mL",
        "dilution": "1:100",
        "application_method": "Pulverizare"
    },
    "message": "Material ad\u0103ugat la ofert\u0103 cu succes"
}
Response (422)
{
    "success": false,
    "message": "Eroare de validare",
    "errors": {
        "materials": "Acela\u0219i material cu aceea\u0219i categorie exist\u0103 deja \u00een ofert\u0103."
    }
}

Removes the quote's line for that material ID (the first one, if it has several categories) and returns its stock.

DELETE
Remove Material Line
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/{id}/materials/{materialId}
Response (200)
{
    "success": true,
    "message": "Material eliminat din ofert\u0103 cu succes"
}
Response (404)
{
    "success": false,
    "message": "Material neg\u0103sit \u00een aceast\u0103 ofert\u0103"
}

Downloads the quote as a Proces Verbal PDF (with the company stamp when apply_stamp_pdf is true).

GET
Proces Verbal PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/{id}/pdf
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"45-proces-verbal-Restaurant-Luigi-SRL-2026-10-01.pdf\""
}
Response (404)
{
    "message": "Resursa solicitat\u0103 nu a fost g\u0103sit\u0103."
}

Downloads one Proces Verbal PDF per selected quote in a ZIP.

POST
Export Proces Verbal PDFs (ZIP)
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/export-bulk-pdf
Request Body
Field Type Rules Description
quote_ids array Required exists:quotes,id Quotes to export
Example Request
{
    "quote_ids": [
        45,
        46
    ]
}
Response (200)
{
    "Content-Type": "application/zip",
    "Content-Disposition": "attachment; filename=\"Export_Procese-Verbale_2026-10-03_12-00-00.zip\""
}
Response (422)
{
    "success": false,
    "message": "Nicio ofert\u0103 selectat\u0103",
    "errors": {
        "quote_ids": "Trebuie selectat\u0103 cel pu\u021bin o ofert\u0103 valid\u0103."
    }
}

Downloads the quote list as PDF. Accepts the same filters as List Quotes.

GET
Export Quote List PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/export-pdf
Parameters
Name Type Required Description
search string Optional Quote number or client name
status, client_id, user_id, date_from, date_to mixed Optional Same as List Quotes
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"Export_Procese-Verbale_2026-10-03_12-00-00.pdf\""
}

Downloads the quote list as CSV. Accepts the same filters as List Quotes.

GET
Export Quote List CSV
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/quotes/export-csv
Parameters
Name Type Required Description
search string Optional Quote number or client name
status, client_id, user_id, date_from, date_to mixed Optional Same as List Quotes
Response (200)
{
    "Content-Type": "text/csv",
    "Content-Disposition": "attachment; filename=\"Export_Procese-Verbale_2026-10-03_12-00-00.csv\""
}

Reports

Read-only reports, each with a PDF export taking the same filters.

Quotes that used materials, oldest first, with their lines. Paginated, 50 per page by default.

GET
Materials Used
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/materials-used
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
client_id integer Optional Filter by client
user_id integer Optional Filter by operator
procedure_type string Optional Only quotes with a line of this category
material_id integer Optional Only quotes using this material
per_page integer Optional Items per page (default 50)
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "nr_crt": 1,
                "quote_number": "QT-2026-00045",
                "client_name": "Restaurant Luigi SRL",
                "procedure_date": "2026-10-01",
                "procedure_time": "10:00",
                "operator_name": "Ion Popescu",
                "materials": [
                    {
                        "material": "Deltamethrin 2.5",
                        "lot": "LOT-001",
                        "nr_act_administrativ": "Aviz 123/2026",
                        "capacity_consumed": "250.00 mL"
                    }
                ]
            }
        ],
        "per_page": 50,
        "total": 1,
        "last_page": 1
    },
    "message": "Raport materiale utilizate preluat cu succes"
}

Downloads the same report (all rows, same filters) as PDF.

GET
Materials Used PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/materials-used/export-pdf
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
client_id integer Optional Filter by client
user_id integer Optional Filter by operator
procedure_type string Optional Only quotes with a line of this category
material_id integer Optional Only quotes using this material
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"Export_Raport_Materiale_Folosite_2026-10-03_12-00-00.pdf\""
}

Schedules, oldest first. Paginated, 50 per page by default.

GET
Schedules
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/schedules
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
client_id integer Optional Filter by client
user_id integer Optional Filter by operator
intervention_type string Optional Exact type of intervention
per_page integer Optional Items per page (default 50)
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 12,
                "client_name": "Restaurant Luigi SRL",
                "address": "Str. Florilor 1, Bucure\u0219ti",
                "phone": "0712345678",
                "representative": "Luigi Rossi",
                "intervention_type": "Deratizare",
                "date": "2026-11-03"
            }
        ],
        "per_page": 50,
        "total": 1,
        "last_page": 1
    },
    "message": "Raport program\u0103ri preluat cu succes"
}

Downloads the same report (all rows, same filters) as PDF.

GET
Schedules PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/schedules/export-pdf
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
client_id integer Optional Filter by client
user_id integer Optional Filter by operator
intervention_type string Optional Exact type of intervention
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"Export_Raport_Programari_2026-10-03_12-00-00.pdf\""
}

One row per variant with initial, used and remaining stock. Paginated, 50 per page by default.

GET
Stock
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/stock
Parameters
Name Type Required Description
material_id integer Optional Filter by material
date_expiration_from date Optional Expiring on or after
date_expiration_to date Optional Expiring on or before
date_from date Optional Acquired on or after
date_to date Optional Acquired on or before
per_page integer Optional Items per page (default 50)
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 3,
                "variant_id": 7,
                "material_name": "Deltamethrin 2.5",
                "variant_capacity": "1000 mL",
                "quantity": 2,
                "invoice": "FCT-001",
                "lot": "LOT-001",
                "date_acquisition": "2026-01-10",
                "date_expiration": "2027-01-10",
                "stoc_total": 3000,
                "stoc_remaining": 2750,
                "total_procedures_qty": 250,
                "available_qty": 2750
            }
        ],
        "per_page": 50,
        "total": 1,
        "last_page": 1
    },
    "message": "Raport stoc preluat cu succes"
}

Downloads the same report (all rows, same filters) as PDF.

GET
Stock PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/stock/export-pdf
Parameters
Name Type Required Description
material_id integer Optional Filter by material
date_expiration_from date Optional Expiring on or after
date_expiration_to date Optional Expiring on or before
date_from date Optional Acquired on or after
date_to date Optional Acquired on or before
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"Export_Raport_Stoc_2026-10-03_12-00-00.pdf\""
}

Materials by name with their number of variants. With a period, only materials with ledger movements in it, and movements_count counts those. Paginated, 50 per page by default.

GET
Storage Sheet
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/storage-sheet
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
unit_measure string Optional Filter by unit
per_page integer Optional Items per page (default 50)
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 3,
                "material_name": "Deltamethrin 2.5",
                "unit_measure": "mL",
                "variants_count": 1,
                "movements_count": 4
            }
        ],
        "per_page": 50,
        "total": 1,
        "last_page": 1
    },
    "message": "Raport fi\u0219\u0103 depozit preluat cu succes"
}

Downloads the same report (all rows, same filters) as PDF.

GET
Storage Sheet PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/storage-sheet/export-pdf
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
unit_measure string Optional Filter by unit
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"Export_Fisa_Depozit_2026-10-03_12-00-00.pdf\""
}

Clients by name with contracted procedures and their latest visit/quote date. Dates filter on when the client was created. Paginated, 50 per page by default.

GET
Clients
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/clients
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
client_id integer Optional One client
client_category_id integer Optional Filter by category
per_page integer Optional Items per page (default 50)
Response (200)
{
    "success": true,
    "data": {
        "current_page": 1,
        "data": [
            {
                "id": 5,
                "client_name": "Restaurant Luigi SRL",
                "cui": "RO123456",
                "phone": "0712345678",
                "contact_person": "Luigi Rossi",
                "address": "Str. Florilor 1, Bucure\u0219ti",
                "procedures": "Deratizare, Dezinsec\u021bie",
                "date": "2026-11-03"
            }
        ],
        "per_page": 50,
        "total": 1,
        "last_page": 1
    },
    "message": "Raport clien\u021bi preluat cu succes"
}

Downloads the same report (all rows, same filters) as PDF.

GET
Clients PDF
Auth
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/reports/clients/export-pdf
Parameters
Name Type Required Description
date_from date Optional From date (inclusive)
date_to date Optional To date (inclusive)
client_id integer Optional One client
client_category_id integer Optional Filter by category
Response (200)
{
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=\"Export_Raport_Clienti_2026-10-03_12-00-00.pdf\""
}

System

System health and status, and the operator kill switch.

Database connectivity and runtime info. HTML in a browser, JSON with Accept: application/json; 503 when unhealthy.

GET
Health Check
Public
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/health
Response (200)
{
    "status": "healthy",
    "timestamp": "2026-10-03T12:00:00.000000Z",
    "checks": {
        "database": {
            "status": "ok",
            "response_time": "1.2ms"
        }
    },
    "system": {
        "php_version": "8.3.6",
        "laravel_version": "12.x",
        "environment": "production"
    }
}

Takes the whole backend offline or brings it back (same flag as `php artisan killswitch:down|up`). While it is down every other request, from every user and API key, gets 503; this endpoint and the page at GET /kill-switch stay reachable. Authenticated by KILL_SWITCH_SECRET in the body, not a Bearer token, because login is blocked while down. Answers 404 when KILL_SWITCH_SECRET is not set (or shorter than 32 characters). Rate limited per IP.

POST
Kill Switch
Public
Endpoint URL
URL
https://pest-control-backend-development.up.railway.app/kill-switch
Request Body
Field Type Rules Description
secret string Required The KILL_SWITCH_SECRET environment variable
action string Required in:status,down,up status only reads the state
confirm boolean accepted (required for down/up) Must be true to change the state
Example Request
{
    "secret": "<KILL_SWITCH_SECRET>",
    "action": "down",
    "confirm": true
}
Response (200)
{
    "success": true,
    "message": "Backend-ul a fost oprit. Toate cererile primesc 503 p\u00e2n\u0103 la repornire.",
    "data": {
        "active": true,
        "changed_via": "phone",
        "changed_at": "2026-10-04T15:00:00+03:00"
    }
}
Response (403)
{
    "success": false,
    "message": "Cheie de acces gre\u0219it\u0103."
}
Response (422)
{
    "message": "Confirma\u021bi ac\u021biunea (confirm: true).",
    "errors": {
        "confirm": [
            "Confirma\u021bi ac\u021biunea (confirm: true)."
        ]
    }
}
Response (503)
{
    "success": false,
    "message": "Serviciul este momentan indisponibil. V\u0103 rug\u0103m s\u0103 reveni\u021bi mai t\u00e2rziu."
}