cldt / laravel-scorimmo
API Wrapper for the Scorimmo API
Requires
- php: ^8.0
- illuminate/contracts: ^8.77|^9.0|^10.0|^11.0|^12.0
- spatie/laravel-package-tools: ^1.9.0
- spatie/laravel-webhook-client: ^3.1.0
Requires (Dev)
- nunomaduro/collision: ^5.5|^6.0|^7.0|^8.0
- orchestra/testbench: ^6.24|^7.0|^8.0|^9.0
- pestphp/pest: ^1.21|^2.34
- spatie/laravel-ray: ^1.29
- spatie/pest-plugin-test-time: ^1.0|^2.0
This package is auto-updated.
Last update: 2026-03-06 14:36:12 UTC
README
A Laravel wrapper for the Scorimmo API — a lead management platform for real estate professionals.
This package provides a fluent API client and a webhook handler built on top of spatie/laravel-webhook-client.
Installation
Install the package via Composer:
composer require cldt/laravel-scorimmo
Publish the configuration file:
php artisan vendor:publish --tag="scorimmo-config"
If you plan to use webhooks, publish and run the migration:
php artisan vendor:publish --tag="scorimmo-migrations"
php artisan migrate
Configuration
Add the following environment variables to your .env file:
# API credentials SCORIMMO_ENDPOINT=https://pro.scorimmo.com/ SCORIMMO_USERNAME=your-username SCORIMMO_PASSWORD=your-password # Or provide a token directly (bypasses login) SCORIMMO_API_TOKEN=your-jwt-token # Webhooks SCORIMMO_WEBHOOK_PATH=/webhook/scorimmo SCORIMMO_WEBHOOK_VERIFY_TOKEN=true SCORIMMO_WEBHOOK_TOKEN=your-webhook-secret
Usage
Authentication
Scorimmo uses JWT Bearer tokens. You can either set SCORIMMO_API_TOKEN in your .env, or authenticate programmatically:
use CLDT\Scorimmo\ScorimmoFacade as Scorimmo; // Option 1: Token set via SCORIMMO_API_TOKEN env variable — works out of the box $leads = Scorimmo::lead()->list(); // Option 2: Login to obtain a token $response = Scorimmo::auth()->login(); $token = $response->getData()['token']; // Then use it $scorimmo = Scorimmo::build()->withToken($token); $leads = $scorimmo->lead()->list();
Leads
List all leads
$response = Scorimmo::lead()->list(); $response = Scorimmo::lead()->list([ 'limit' => 50, 'page' => 2, 'order' => 'desc', 'orderby' => 'created_at', 'search' => 'Dupont', ]); $leads = $response->getData(); if ($response->isPaginated()) { $pagination = $response->getPagination(); $pagination->getTotalItems(); $pagination->getTotalPages(); $pagination->getCurrentPage(); }
List leads by store
$response = Scorimmo::lead()->listByStore(42, [ 'limit' => 20, 'page' => 1, ]);
Get a single lead
$response = Scorimmo::lead()->getOne(123); $lead = $response->getData();
Create a lead
$response = Scorimmo::lead()->create([ 'store_id' => 1, 'properties' => [ [ 'type' => 'Appartement', 'price' => 250000, 'area' => 65, 'zipcode' => '75011', 'city' => 'Paris', ], ], 'customer' => [ 'last_name' => 'Dupont', 'first_name' => 'Jean', 'email' => 'jean.dupont@example.com', 'phone' => '0612345678', ], 'interest' => 'TRANSACTION', 'origin' => 'Website', 'seller' => [ 'email' => 'agent@example.com', ], 'comment' => 'Interested in 2-bedroom apartments', ]); if ($response->hasError()) { echo $response->getMessage(); }
Update a lead
$response = Scorimmo::lead()->update(123, [ 'customer' => [ 'phone' => '0698765432', ], 'comment' => 'Updated phone number', ]);
$response = Scorimmo::email()->send([ 'to_email' => 'client@example.com', 'subject' => 'Your property estimate', 'html' => '<h1>Hello</h1><p>Here is your estimate.</p>', 'last_name' => 'Dupont', 'first_name' => 'Jean', 'reference' => 'REF-123', ]);
Web Callback
$response = Scorimmo::webCallback()->launch([ 'key' => 'your-wcb-user-key', 'number_to_call' => '0612345678', ]);
Handling errors
Every API method returns a ScorimmoApiResponse object:
$response = Scorimmo::lead()->getOne(999); if ($response->hasError()) { $response->getStatusCode(); // 404 $response->getMessage(); // Error message $response->getVerbose(); // Detailed error } else { $response->getData(); // Lead data as array $response->count(); // Number of items $response->getFirst(); // First item (for lists) $response->getLast(); // Last item (for lists) $response->toArray(); // Full response as array $response->toString(); // JSON string of data }
Webhooks
The package automatically registers a POST route at the configured webhook_path (default: /webhook/scorimmo).
Available events
| Event | Description |
|---|---|
new_lead |
A new lead is created |
update_lead |
A lead is updated |
new_comment |
A comment is added to a lead |
new_reminder |
A reminder is created |
new_rdv |
An appointment is scheduled |
closure_lead |
A lead is closed |
Using Laravel events
Every incoming webhook fires a Laravel event named scorimmo::{event_name}:
// In EventServiceProvider protected $listen = [ 'scorimmo::new_lead' => [ \App\Listeners\HandleNewLead::class, ], 'scorimmo::closure_lead' => [ \App\Listeners\HandleLeadClosure::class, ], ];
// App\Listeners\HandleNewLead.php use CLDT\Scorimmo\Models\ScorimmoWebhookCall; class HandleNewLead { public function handle(ScorimmoWebhookCall $webhookCall) { $leadId = $webhookCall->payload('id'); $customer = $webhookCall->payload('customer'); // ... } }
Using jobs
You can also map events to queued jobs in config/scorimmo.php:
'webhook_jobs' => [ 'new_lead' => \App\Jobs\Scorimmo\HandleNewLeadJob::class, 'update_lead' => \App\Jobs\Scorimmo\HandleLeadUpdateJob::class, 'closure_lead' => \App\Jobs\Scorimmo\HandleLeadClosureJob::class, // Use '*' to handle all events with a single job // '*' => \App\Jobs\Scorimmo\HandleAllWebhooksJob::class, ],
Your job should accept a ScorimmoWebhookCall instance:
// App\Jobs\Scorimmo\HandleNewLeadJob.php use CLDT\Scorimmo\Models\ScorimmoWebhookCall; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class HandleNewLeadJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct( public ScorimmoWebhookCall $webhookCall ) {} public function handle() { $payload = $this->webhookCall->payload(); // Process the new lead... } }
Webhook payload examples
new_lead / update_lead
{
"event": "new_lead",
"id": 123,
"store_id": "1",
"customer": {
"title": "M.",
"first_name": "Jean",
"last_name": "Dupont",
"email": "jean@example.com",
"phone": "0612345678",
"other_phone_number": null,
"zip_code": "75011",
"city": "Paris"
},
"seller": {
"id": 42,
"first_name": "Marie",
"last_name": "Martin",
"email": "marie@agency.com"
},
"properties": [
{
"id": 456,
"type": "Appartement",
"price": 250000,
"area": 65,
"nb_rooms": 3,
"reference": "REF-789",
"address": "10 rue de la Paix, 75002 Paris",
"link": "https://example.com/property/456"
}
],
"comments": [
{
"content": "First contact by phone",
"created_at": "2025-01-15T10:30:00+01:00"
}
],
"origin": "Website",
"interest": "TRANSACTION",
"status": "new",
"purpose": "Achat",
"contact_type": "email",
"created_at": "2025-01-15T10:30:00+01:00"
}
new_comment
{
"event": "new_comment",
"lead_id": 123,
"external_lead_id": "EXT-456",
"comment": "Client called back, very interested",
"created_at": "2025-01-15T14:00:00+01:00"
}
new_reminder
{
"event": "new_reminder",
"lead_id": 123,
"external_lead_id": "EXT-456",
"created_at": "2025-01-15T14:00:00+01:00",
"start_time": "2025-01-20T09:00:00+01:00",
"detail": "recontact",
"comment": "Follow up on property visit"
}
new_rdv
{
"event": "new_rdv",
"lead_id": 123,
"external_lead_id": "EXT-456",
"created_at": "2025-01-15T14:00:00+01:00",
"start_time": "2025-01-20T10:00:00+01:00",
"location": "10 rue de la Paix, 75002 Paris",
"detail": "Visite",
"comment": "Apartment visit with client"
}
closure_lead
{
"event": "closure_lead",
"lead_id": 123,
"external_lead_id": "EXT-456",
"status": "SUCCESS",
"close_reason": "Property sold"
}
Pruning old webhook calls
The ScorimmoWebhookCall model uses Laravel's MassPrunable trait. Old records are automatically deleted based on the webhook_prune_calls_after_days config value (default: 30 days).
Make sure the Laravel pruning command is scheduled:
// app/Console/Kernel.php $schedule->command('model:prune', ['--model' => \CLDT\Scorimmo\Models\ScorimmoWebhookCall::class])->daily();
API Reference
Available methods
| Method | HTTP | Endpoint | Description |
|---|---|---|---|
auth()->login($username, $password) |
POST | /api/login_check |
Obtain a JWT token |
lead()->list($params) |
GET | /api/leads |
List leads (paginated) |
lead()->getOne($id) |
GET | /api/lead/{id} |
Get a single lead |
lead()->create($data) |
POST | /api/lead |
Create a lead |
lead()->update($id, $data) |
PUT | /api/lead/{id} |
Update a lead |
lead()->listByStore($storeId, $params) |
GET | /api/stores/{id}/leads |
List leads for a store |
email()->send($data) |
POST | /api/email |
Send an email |
webCallback()->launch($data) |
POST | /api/wcb |
Launch a web callback |
Search parameters for leads
The search parameter supports keyed searches:
// Global search Scorimmo::lead()->list(['search' => 'Dupont']); // Keyed searches Scorimmo::lead()->list(['search' => ['email' => 'jean@example.com']]); Scorimmo::lead()->list(['search' => ['status' => 'new']]); Scorimmo::lead()->list(['search' => ['seller_id' => 42]]);
Available search keys: id, type, customer_firstname, customer_lastname, email, phone, origin, interest, seller_firstname, seller_lastname, seller_id, created_at, status, closed_date, updated_at, anonymized_at, seller_present_on_creation, transfered, external_lead_id, external_customer_id, other_phone_number, reference.
ScorimmoApiResponse
| Method | Return type | Description |
|---|---|---|
hasError() |
bool |
Whether the request failed |
getStatusCode() |
int |
HTTP status code |
getMessage() |
string |
Error message |
getVerbose() |
string |
Detailed error message |
getData() |
array |
Response data |
getFirst() |
?array |
First item in data |
getLast() |
?array |
Last item in data |
count() |
int |
Number of items |
isPaginated() |
bool |
Whether response has pagination |
getPagination() |
ScorimmoApiPagination |
Pagination details |
toArray() |
array |
Full response as array |
toString() |
string |
Data as JSON string |
ScorimmoApiPagination
| Method | Return type | Description |
|---|---|---|
getLimit() |
int |
Items per page |
getCurrentPage() |
int |
Current page number |
getTotalItems() |
int |
Total number of items |
getTotalPages() |
int |
Total number of pages |
getCurrentPageResults() |
int |
Items on current page |
getNextPage() |
?string |
Next page URL |
getPreviousPage() |
?string |
Previous page URL |
Requirements
- PHP >= 8.0
- Laravel >= 8.77
License
The MIT License (MIT). Please see License File for more information.