Esta documentação descreve os principais endpoints da API para clientes e prestadores, incluindo autenticação, serviços e pedidos.
š Autenticação & Registro
Registro de Cliente
POST domain/api/register
Content-Type: application/json
{
"name": "João Cliente",
"email": "joao@example.com",
"password": "123456",
"phone": "900000001",
"role": "cliente"
}
Registro de Prestador
POST domain/api/register
Content-Type: application/json
Accept: application/json
{
"name": "Teste",
"email": "provider@example.com",
"phone": "99999999",
"password": "123456",
"password_confirmation": "123456",
"role": "provider"
}
Login
POST domain/api/login
Content-Type: application/json
{
"email": "provider@example.com",
"password": "123456"
}
Resposta (exemplo)
{
"token": "5|SeAdY03gxnjCVXrOP6tp02j2N9riqP64gVucptaL6c8d81ed",
"user": {
"id": 1,
"name": "Teste",
"role": "provider"
}
}
š ļø Criar ServiƧo do Prestador (Provider Service)
Endpoint usado para o prestador cadastrar o seu serviƧo, incluindo fotos em Base64.
Endpoint
POST domain/api/provider-services
Content-Type: application/json
Authorization: Bearer {TOKEN}
Accept: application/json
Body
{
"provider_id": 1,
"service_id": 1,
"category_id": 1,
"price_range": "10.000 - 20.000 Kz",
"description": "Manutenção e instalação de equipamentos",
"is_active": true,
"photos": [
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAA...",
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
]
}
ObservaƧƵes:
category_idé obrigatório e deve referenciar uma categoria existente emservice_categories.photosé opcional e recebe um array de imagens em Base64.- Cada imagem serÔ salva no servidor e associada ao serviço via tabela provider_service_images.
- O usuÔrio autenticado deve ser o próprio prestador.
Resposta (exemplo)
{
"message": "ServiƧo cadastrado com sucesso",
"data": {
"id": 3,
"provider_id": 1,
"service_id": 1,
"price_range": "10.000 - 20.000 Kz",
"description": "Manutenção e instalação de equipamentos",
"is_active": true,
"created_at": "2025-11-25T12:00:00.000000Z",
"updated_at": "2025-11-25T12:00:00.000000Z",
"images": [
"https://domain.com/imagens/9837sd87sd.jpg",
"https://domain.com/imagens/77asdas8d7sa.png"
]
}
}
š ServiƧos
Buscar serviços por localização + nome
GET domain/api/services?lat=-8.838&lng=13.234&service_name=canaliz
Retorna prestadores e serviƧos filtrados por latitude, longitude e nome do serviƧo.
Buscar todos os serviƧos (sem filtros)
GET domain/api/services
Retorna todos os serviƧos cadastrados com seus respectivos prestadores.
Detalhe de um serviƧo
GET domain/api/services/1
Retorna as informaƧƵes detalhadas de um serviƧo especĆfico.
š Categorias
Listar todas as categorias
GET domain/api/categories
Accept: application/json
Retorna todas as categorias disponĆveis para serem utilizadas ao cadastrar serviƧos de prestadores.
Resposta (exemplo)
{
"success": true,
"count": 5,
"data": [
{
"id": 1,
"name": "Canalização",
"created_at": "2025-09-01T10:00:00.000000Z",
"updated_at": "2025-09-01T10:00:00.000000Z"
},
{
"id": 2,
"name": "Eletricidade",
"created_at": "2025-09-01T10:00:00.000000Z",
"updated_at": "2025-09-01T10:00:00.000000Z"
}
]
}
ObservaƧƵes:
- Este endpoint não requer autenticação.
- As categorias retornadas devem ser usadas no campo
category_idao criar um Provider Service.
š¦ Pedidos (Requests)
Criar novo pedido
POST domain/api/requests
Content-Type: application/json
Authorization: Bearer {TOKEN}
Accept: application/json
{
"service_provider_id": 1,
"description": "teste",
"location": "Luanda, Vila Alice"
}
Resposta (exemplo)
{
"message": "Pedido criado com sucesso!",
"data": {
"id": 15,
"client_id": 2,
"provider_id": 1,
"service_id": 1,
"status": "pending",
"description": "teste",
"location": "Luanda, Vila Alice",
"scheduled_at": null,
"created_at": "2025-09-03T20:15:10.000000Z",
"updated_at": "2025-09-03T20:15:10.000000Z"
}
}
Listar pedidos do cliente autenticado
GET domain/api/requests
Authorization: Bearer {TOKEN}
Accept: application/json
Resposta (exemplo)
{
"success": true,
"count": 2,
"data": [
{
"id": 15,
"service": {
"id": 1,
"name": "Canalização",
"category": "ServiƧos DomƩsticos"
},
"provider": {
"id": 1,
"name": "Prestador Teste"
},
"status": "pending",
"location": "Luanda, Vila Alice",
"created_at": "2025-09-03T20:15:10.000000Z"
}
]
}
š Atualizar Estado de um Pedido
Este endpoint permite alterar o estado de um pedido conforme o tipo do usuƔrio autenticado:
- Provider pode alterar para:
accepted,in_progress,completed - Cliente só pode alterar para:
cancelled
š Estados PossĆveis
pendingā Criado pelo cliente, aguardando ação do provideracceptedā Provider aceitou o pedido- ā ļø Ação automĆ”tica: Chat Ć© criado automaticamente e mensagem de boas-vindas Ć© enviada do prestador para o cliente
in_progressā Provider iniciou o trabalhocompletedā Provider concluiu o serviƧo- ā ļø Ação automĆ”tica: Mensagem solicitando avaliação de satisfação Ć© enviada automaticamente
cancelledā Cancelado pelo cliente
š” Endpoint
PUT domain/api/requests/{id}/status
Content-Type: application/json
Authorization: Bearer {TOKEN}
Accept: application/json
Body
{
"status": "accepted"
}
ā Exemplo de Resposta (Provider)
{
"message": "Status atualizado com sucesso",
"data": {
"id": 15,
"status": "accepted",
"updated_at": "2025-12-06T11:22:10.000000Z"
}
}
ā Exemplo de Resposta (Cliente cancelando)
{
"message": "Pedido cancelado com sucesso",
"data": {
"id": 15,
"status": "cancelled"
}
}
ā Exemplo de resposta nĆ£o permitida
{
"message": "Clientes só podem cancelar pedidos."
}
š Listar Planos
Retorna todos os planos disponĆveis para subscrição por parte dos prestadores.
š” Endpoint
GET domain/api/plans
Accept: application/json
ā Exemplo de Resposta
{
"success": true,
"data": [
{
"id": 1,
"name": "Plano Mensal",
"price": "15000.00",
"duration_days": 30,
"features": [
"Mais visibilidade",
"Destaque nas buscas"
]
},
{
"id": 2,
"name": "Plano Trimestral",
"price": "40000.00",
"duration_days": 90,
"features": [
"Economia 10%",
"Maior prioridade"
]
}
]
}
š Criar Subscrição
O prestador escolhe um plano e envia o comprovativo de pagamento para validação no backoffice.
š” Endpoint
POST domain/api/subscriptions
Accept: application/json
Authorization: Bearer
Content-Type: multipart/form-data
š¦ Body (multipart/form-data)
plan_id: 1
proof_file: (jpg, png, jpeg, pdf)
ā Exemplo via REST Client
POST domain/api/subscriptions
Authorization: Bearer TOKEN
Content-Type: multipart/form-data
--boundary
Content-Disposition: form-data; name="plan_id"
1
--boundary
Content-Disposition: form-data; name="proof_file"; filename="comprovativo.jpg"
Content-Type: image/jpeg
< /caminho/local/do/ficheiro/comprovativo.jpg
--boundary--
ā Exemplo de Resposta
{
"message": "Subscrição criada e enviada para validação.",
"data": {
"id": 8,
"plan_id": 1,
"status": "pending_validation",
"proof_file": "uploads/proofs/proof_8.jpg"
}
}
š Minha Subscrição (My Subscription)
Retorna a subscrição ativa do prestador autenticado, incluindo informações do plano, datas e status.
š” Endpoint
GET domain/api/subscriptions
Authorization: Bearer
Accept: application/json
ā Exemplo de Resposta (Prestador com subscrição ativa)
{
"success": true,
"subscription": {
"id": 5,
"provider_id": 12,
"plan": {
"id": 1,
"name": "Plano Mensal",
"price": "15000.00",
"duration_days": 30,
"features": [
"Destaque nas buscas",
"Atendimento prioritƔrio",
"Mais pedidos"
]
},
"status": "active",
"start_date": "2025-12-01",
"end_date": "2026-01-01"
}
}
ā Exemplo sem subscrição
{
"success": true,
"subscription": null,
"message": "Nenhuma subscrição ativa encontrada."
}
š¬ Chat entre Cliente e Prestador
O chat só pode ser criado e utilizado quando a reserva (request) estiver no status accepted.
- Apenas o cliente do serviƧo pode enviar e ler mensagens
- Apenas o prestador do serviƧo pode enviar e ler mensagens
- Quando o prestador aceita o serviƧo: O chat Ʃ criado automaticamente e uma mensagem de boas-vindas Ʃ enviada do prestador para o cliente
- Quando o serviƧo Ć© concluĆdo: Uma mensagem automĆ”tica Ć© enviada solicitando avaliação de satisfação
Criar Chat
POST domain/api/chats
Content-Type: application/json
Authorization: Bearer {TOKEN}
Accept: application/json
{
"request_id": 1
}
Resposta (exemplo)
{
"message": "Chat criado com sucesso.",
"data": {
"id": 1,
"request_id": 1,
"created_at": "2025-12-06T10:30:00.000000Z",
"request": {
"id": 1,
"status": "accepted"
},
"messages": []
}
}
ā Erro se request nĆ£o estiver 'accepted'
{
"message": "O chat só pode ser criado quando a reserva estiver no status \"accepted\".",
"current_status": "pending"
}
Ver Histórico do Chat
GET domain/api/chats/{id}
Authorization: Bearer {TOKEN}
Accept: application/json
Resposta (exemplo)
{
"chat": {
"id": 1,
"request_id": 1,
"request_status": "accepted",
"created_at": "2025-12-06T10:30:00.000000Z"
},
"messages": [
{
"id": 1,
"sender": {
"id": 2,
"name": "João Cliente",
"email": "joao@example.com"
},
"message_text": "OlĆ”, quando podemos agendar?",
"message_type": "text",
"sent_at": "2025-12-06T10:35:00.000000Z",
"created_at": "2025-12-06T10:35:00.000000Z"
},
{
"id": 2,
"sender": {
"id": 1,
"name": "Prestador Teste",
"email": "provider@example.com"
},
"message_text": "Podemos agendar para amanhã às 14h.",
"message_type": "text",
"sent_at": "2025-12-06T10:40:00.000000Z",
"created_at": "2025-12-06T10:40:00.000000Z"
}
],
"participants": {
"client": {
"id": 2,
"name": "João Cliente"
},
"provider": {
"id": 1,
"name": "Prestador Teste"
}
}
}
Enviar Mensagem
POST domain/api/chats/{id}/messages
Content-Type: application/json
Authorization: Bearer {TOKEN}
Accept: application/json
{
"message_text": "OlƔ, quando podemos agendar o serviƧo?",
"message_type": "text"
}
Tipos de mensagem: text, image, file
Resposta (exemplo)
{
"message": "Mensagem enviada com sucesso.",
"data": {
"id": 3,
"sender": {
"id": 2,
"name": "João Cliente",
"email": "joao@example.com"
},
"message_text": "OlƔ, quando podemos agendar o serviƧo?",
"message_type": "text",
"sent_at": "2025-12-06T10:45:00.000000Z",
"created_at": "2025-12-06T10:45:00.000000Z"
}
}
ā Erro se request nĆ£o estiver 'accepted'
{
"message": "Mensagens só podem ser enviadas quando a reserva estiver no status \"accepted\".",
"current_status": "pending"
}
ā” Chat em Tempo Real (WebSocket)
O sistema utiliza Laravel Broadcasting para comunicação em tempo real. Quando uma mensagem é enviada, um evento é disparado automaticamente para todos os participantes do chat.
Configure o driver de broadcasting no arquivo .env:
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=your-app-id
PUSHER_APP_KEY=your-app-key
PUSHER_APP_SECRET=your-app-secret
PUSHER_APP_CLUSTER=mt1
Cada chat utiliza um canal privado: private-chat.{chatId}
Apenas o cliente e o prestador do serviƧo podem acessar o canal.
Quando uma mensagem Ć© enviada, o evento message.sent Ć© disparado no canal privado com os seguintes dados:
{
"id": 3,
"chat_id": 1,
"sender": {
"id": 2,
"name": "João Cliente",
"email": "joao@example.com"
},
"message_text": "OlĆ”, quando podemos agendar?",
"message_type": "text",
"sent_at": "2025-12-06T10:45:00.000000Z",
"created_at": "2025-12-06T10:45:00.000000Z"
}
Para integrar com Flutter, use o pacote pusher_channels_flutter ou laravel_echo:
// Exemplo com pusher_channels_flutter
import 'package:pusher_channels_flutter/pusher_channels_flutter.dart';
// Conectar ao Pusher
final pusher = PusherChannelsFlutter.getInstance();
await pusher.init(
apiKey: 'YOUR_PUSHER_KEY',
cluster: 'mt1',
onConnectionStateChange: onConnectionStateChange,
onError: onError,
onSubscriptionSucceeded: onSubscriptionSucceeded,
onEvent: onEvent,
onSubscriptionError: onSubscriptionError,
onDecryptionFailure: onDecryptionFailure,
onMemberAdded: onMemberAdded,
onMemberRemoved: onMemberRemoved,
);
// Autenticar e subscrever ao canal privado
await pusher.subscribe(
channelName: 'private-chat.1',
onEvent: (event) {
if (event.eventName == 'message.sent') {
// Processar nova mensagem recebida
final messageData = jsonDecode(event.data);
// Atualizar UI com nova mensagem
}
},
);
// Autenticação do canal privado
// Você precisa implementar um endpoint de autenticação
// POST /broadcasting/auth com o token do usuƔrio
O Laravel jÔ fornece automaticamente o endpoint de autenticação em:
POST /broadcasting/auth
Envie o token de autenticação no header Authorization: Bearer {TOKEN} e o nome do canal no body.
ā AvaliaƧƵes (Reviews)
- Apenas o cliente pode avaliar o serviƧo
- Apenas Ć© possĆvel avaliar serviƧos com status
completed - Cada serviƧo pode ser avaliado apenas uma vez
- A avaliação atualiza automaticamente o rating médio do prestador
Criar Avaliação
POST domain/api/reviews
Content-Type: application/json
Authorization: Bearer {TOKEN}
Accept: application/json
{
"request_id": 1,
"rating": 5,
"comment": "Excelente serviƧo! Muito profissional e pontual."
}
Parâmetros:
request_id(obrigatório) - ID do pedido concluĆdorating(obrigatório) - Nota de 1 a 5comment(opcional) - ComentĆ”rio sobre o serviƧo (mĆ”x. 1000 caracteres)
Resposta (exemplo)
{
"message": "Avaliação criada com sucesso.",
"data": {
"id": 1,
"request_id": 1,
"client_id": 2,
"provider_id": 1,
"rating": 5,
"comment": "Excelente serviƧo! Muito profissional e pontual.",
"created_at": "2025-12-06T12:00:00.000000Z",
"client": {
"id": 2,
"name": "João Cliente"
},
"provider": {
"id": 1,
"name": "Prestador Teste"
}
}
}
ā Erro se serviƧo nĆ£o estiver concluĆdo
{
"message": "Apenas Ć© possĆvel avaliar serviƧos concluĆdos.",
"current_status": "in_progress"
}
ā Erro se jĆ” foi avaliado
{
"message": "Este serviƧo jƔ foi avaliado.",
"data": { ... }
}
Listar AvaliaƧƵes de um Prestador
GET domain/api/providers/{id}/reviews
Accept: application/json
Resposta (exemplo)
{
"success": true,
"stats": {
"total": 15,
"average": 4.5,
"distribution": {
"5": 8,
"4": 5,
"3": 2,
"2": 0,
"1": 0
}
},
"data": [
{
"id": 1,
"request_id": 1,
"client_id": 2,
"provider_id": 1,
"rating": 5,
"comment": "Excelente serviƧo!",
"created_at": "2025-12-06T12:00:00.000000Z",
"client": {
"id": 2,
"name": "João Cliente"
},
"request": {
"id": 1,
"service": {
"id": 1,
"name": "Canalização"
}
}
}
]
}
š ObservaƧƵes
- O campo role no registro define se o usuƔrio Ʃ
clienteouprovider. - Authorization deve ser sempre enviado como:
Bearer {TOKEN} - O campo
service_provider_idfaz referĆŖncia Ć tabela provider_services. - O campo
scheduled_atpode ser usado para agendamentos futuros (ex.: "2025-09-05 15:00:00").