---
title: Référence API
subtitle: Connectez votre site web ou des outils externes à Check-in ARTISAN
icon: code-bracket
order: 12
alt_slug: api
excerpt: Utilisez l'API REST de Check-in ARTISAN pour afficher votre profil entreprise, synchroniser clients, chantiers, visites terrain et factures avec vos propres outils.
---

## Présentation

L'API Check-in ARTISAN vous permet d'intégrer votre entreprise de terrain à votre propre site web ou à des applications externes. Que vous souhaitiez afficher votre profil entreprise, synchroniser vos données clients et chantiers, ou exporter vos factures vers votre logiciel de comptabilité, l'API vous donne un accès programmatique complet à vos données.

**Principaux cas d'usage :**

- Afficher les informations de votre entreprise sur votre propre site web.
- Créer un portail client personnalisé.
- Exporter les données de visites terrain et de facturation vers votre logiciel de comptabilité.
- Automatiser des flux de travail avec d'autres outils métiers.

---

## URL de base

Toutes les requêtes API sont adressées à :

```
https://checkinartisan.app/api/v1/
```

Toutes les réponses sont au format JSON. Les dates et horodatages utilisent le format ISO 8601.

---

## Authentification

La plupart des endpoints de l'API nécessitent une authentification via un **jeton Bearer**. Vous générez ces jetons depuis le panneau d'administration, sous **Compte Check-in ARTISAN > Jetons API**.

Incluez le jeton dans l'en-tête `Authorization` de chaque requête authentifiée :

```
Authorization: Bearer votre-jeton-api-ici
```

Chaque jeton est rattaché à une seule entreprise. Vous pouvez créer plusieurs jetons pour la même entreprise (par exemple, un par intégration).

**Bonnes pratiques de sécurité :**

- Traitez les jetons API comme des mots de passe. Ne les incluez jamais dans le code source.
- Utilisez un jeton par intégration pour pouvoir révoquer individuellement les accès.
- Révoquez les jetons inutilisés immédiatement.

---

## Endpoints publics

Ces endpoints ne nécessitent aucune authentification. Ils sont conçus pour une intégration sur des sites publics.

### GET /api/v1/companies/{slug}

Retourne le profil public d'une entreprise.

**Paramètres :** `{slug}` est l'identifiant unique de votre entreprise (visible dans l'URL de votre espace d'administration).

**Réponse :**

```json
{
  "data": {
    "slug": "swift-plumbing",
    "name": "Swift Plumbing & Co.",
    "description": "Plomberie professionnelle pour particuliers et professionnels.",
    "phone": "+33 1 23 45 67 89",
    "mobile": null,
    "email": "contact@swiftplumbing.fr",
    "website": "https://swiftplumbing.fr",
    "address": "12 Rue des Artisans",
    "address2": null,
    "zip_code": "75001",
    "city": "Paris",
    "country": "FR",
    "opening_hours": { "monday": "8:00-18:00" },
    "social": {
      "facebook": null,
      "instagram": "https://instagram.com/swiftplumbing",
      "twitter": null,
      "youtube": null
    },
    "locale": "fr",
    "currency": "EUR",
    "timezone": "Europe/Paris"
  }
}
```

---

## Endpoints authentifiés

Tous les endpoints ci-dessous nécessitent un jeton Bearer valide dans l'en-tête `Authorization`.

---

### GET /api/v1/company

Retourne le profil complet de l'entreprise associée au jeton API, y compris le plan d'abonnement actif.

**Réponse :** identique à l'endpoint public, avec en plus un champ `"plan"` (`"free"`, `"solo"` ou `"pro"`).

---

### Clients

#### GET /api/v1/customers

Liste tous les clients de votre entreprise.

**Paramètres de requête :**

| Paramètre  | Type    | Description |
|------------|---------|-------------|
| `search`   | string  | Filtrer par nom, e-mail ou téléphone. |
| `per_page` | integer | Résultats par page (défaut : 25, max : 100). |
| `page`     | integer | Numéro de page (défaut : 1). |

**Réponse :**

```json
{
  "data": [
    {
      "id": 1,
      "first_name": "Marie",
      "last_name": "Dupont",
      "full_name": "Marie Dupont",
      "email": "marie@exemple.fr",
      "phone": "+33 6 12 34 56 78",
      "mobile": null,
      "address": "12 Rue des Artisans",
      "address2": null,
      "zip_code": "75001",
      "city": "Paris",
      "country": "FR",
      "notes": null,
      "send_sms": true,
      "is_walk_in": false,
      "created_at": "2026-01-15T10:30:00+01:00",
      "updated_at": "2026-01-15T10:30:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 25,
    "total": 72
  }
}
```

#### POST /api/v1/customers

Crée un nouveau client.

**Corps de la requête :**

```json
{
  "first_name": "Marie",
  "last_name": "Dupont",
  "email": "marie@exemple.fr",
  "phone": "+33 6 12 34 56 78",
  "mobile": "+33 7 98 76 54 32",
  "address": "12 Rue des Artisans",
  "address2": "Apt 3B",
  "zip_code": "75001",
  "city": "Paris",
  "country": "FR",
  "notes": "Préfère les rendez-vous le matin.",
  "send_sms": true
}
```

| Champ        | Type    | Obligatoire | Description |
|--------------|---------|-------------|-------------|
| `first_name` | string  | Oui         | Prénom (max 255). |
| `last_name`  | string  | Oui         | Nom (max 255). |
| `email`      | string  | Non         | Adresse e-mail. |
| `phone`      | string  | Non         | Numéro de téléphone (max 50). |
| `mobile`     | string  | Non         | Numéro de portable (max 50). |
| `address`    | string  | Non         | Adresse, ligne 1 (max 255). |
| `address2`   | string  | Non         | Adresse, ligne 2 (max 255). |
| `zip_code`   | string  | Non         | Code postal (max 20). |
| `city`       | string  | Non         | Ville (max 255). |
| `country`    | string  | Non         | Code pays ISO 3166-1 alpha-2 (ex. `"FR"`). |
| `notes`      | string  | Non         | Notes internes (max 5000 caractères). |
| `send_sms`   | boolean | Non         | Inclure ce client dans les rappels SMS. |

**Réponse (201) :** le client créé (mêmes champs que la liste).

#### GET /api/v1/customers/{id}

Récupère un client avec ses chantiers.

**Réponse :** mêmes champs que la liste, avec en plus un tableau `jobs` :

```json
{
  "data": {
    "id": 1,
    "first_name": "Marie",
    "last_name": "Dupont",
    "full_name": "Marie Dupont",
    "email": "marie@exemple.fr",
    "phone": "+33 6 12 34 56 78",
    "mobile": null,
    "address": "12 Rue des Artisans",
    "address2": null,
    "zip_code": "75001",
    "city": "Paris",
    "country": "FR",
    "notes": null,
    "send_sms": true,
    "is_walk_in": false,
    "created_at": "2026-01-15T10:30:00+01:00",
    "updated_at": "2026-01-15T10:30:00+01:00",
    "jobs": [
      { "id": 12, "title": "Réparation plomberie salle de bain" }
    ]
  }
}
```

#### PUT /api/v1/customers/{id}

Met à jour un client. Envoyez uniquement les champs à modifier. Accepte les mêmes champs que `POST /api/v1/customers`, tous optionnels.

#### DELETE /api/v1/customers/{id}

Supprime un client. Retourne `204 No Content`.

---

### Chantiers

#### GET /api/v1/jobs

Liste tous les chantiers de votre entreprise.

**Paramètres de requête :**

| Paramètre     | Type    | Description |
|---------------|---------|-------------|
| `customer_id` | integer | Filtrer par client. |
| `status`      | string  | Filtrer par statut (`draft`, `open`, `in_progress`, `completed`, `cancelled`). |
| `per_page`    | integer | Résultats par page (défaut : 25, max : 100). |
| `page`        | integer | Numéro de page (défaut : 1). |

**Réponse :**

```json
{
  "data": [
    {
      "id": 12,
      "customer_id": 1,
      "job_type_id": 3,
      "title": "Réparation plomberie salle de bain",
      "description": "Remplacement mitigeur et rejointement baignoire.",
      "address": "12 Rue des Artisans, Paris",
      "status": "in_progress",
      "created_at": "2026-02-01T09:00:00+01:00",
      "updated_at": "2026-02-10T14:30:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 2,
    "per_page": 25,
    "total": 47
  }
}
```

#### POST /api/v1/jobs

Crée un nouveau chantier.

| Champ         | Type    | Obligatoire | Description |
|---------------|---------|-------------|-------------|
| `customer_id` | integer | Oui         | Identifiant du client associé au chantier. |
| `title`       | string  | Oui         | Intitulé du chantier (max 255). |
| `job_type_id` | integer | Non         | Identifiant du type de travaux. |
| `description` | string  | Non         | Description du chantier (max 5000). |
| `address`     | string  | Non         | Adresse du chantier (max 255). |
| `status`      | string  | Non         | Statut initial : `draft`, `open`, `in_progress`, `completed` ou `cancelled`. |

**Réponse (201) :** le chantier créé.

#### GET /api/v1/jobs/{id}

Récupère un chantier avec le client, le type de travaux et le nombre de visites terrain.

**Réponse :**

```json
{
  "data": {
    "id": 12,
    "customer_id": 1,
    "job_type_id": 3,
    "title": "Réparation plomberie salle de bain",
    "description": "Remplacement mitigeur et rejointement baignoire.",
    "address": "12 Rue des Artisans, Paris",
    "status": "in_progress",
    "created_at": "2026-02-01T09:00:00+01:00",
    "updated_at": "2026-02-10T14:30:00+01:00",
    "customer": {
      "id": 1,
      "full_name": "Marie Dupont"
    },
    "job_type": {
      "id": 3,
      "name": "Plomberie"
    },
    "site_visits_count": 2
  }
}
```

Le champ `job_type.name` est retourné dans la langue de l'entreprise (`fr` ou `en`).

#### PUT /api/v1/jobs/{id}

Met à jour un chantier. Envoyez uniquement les champs à modifier. Accepte `job_type_id`, `title`, `description`, `address` et `status`.

#### DELETE /api/v1/jobs/{id}

Supprime un chantier. Retourne `204 No Content`.

---

### Visites terrain

#### GET /api/v1/site-visits

Liste les visites terrain de votre entreprise.

**Paramètres de requête :**

| Paramètre     | Type    | Description |
|---------------|---------|-------------|
| `from`        | string  | Date de début du filtre (`YYYY-MM-DD`). |
| `to`          | string  | Date de fin du filtre (`YYYY-MM-DD`). |
| `customer_id` | integer | Filtrer par client. |
| `job_id`      | integer | Filtrer par chantier. |
| `status`      | string  | Filtrer par statut (`scheduled`, `completed`, `cancelled`). |
| `per_page`    | integer | Résultats par page (défaut : 25, max : 100). |
| `page`        | integer | Numéro de page. |

**Réponse :**

```json
{
  "data": [
    {
      "id": 7,
      "job_id": 12,
      "customer_id": 1,
      "team_member_id": 2,
      "scheduled_at": "2026-03-20T09:00:00+01:00",
      "duration_minutes": 120,
      "status": "scheduled",
      "notes": "Le client sera présent dès 9h.",
      "created_at": "2026-03-01T11:00:00+01:00",
      "updated_at": "2026-03-01T11:00:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 25,
    "total": 5
  }
}
```

#### POST /api/v1/site-visits

Crée une nouvelle visite terrain.

| Champ              | Type    | Obligatoire | Description |
|--------------------|---------|-------------|-------------|
| `job_id`           | integer | Oui         | Identifiant du chantier associé à cette visite. |
| `scheduled_at`     | string  | Oui         | Date et heure planifiées (ISO 8601, ex. `"2026-03-20T09:00:00"`). |
| `customer_id`      | integer | Non         | Identifiant du client (par défaut, le client du chantier). |
| `duration_minutes` | integer | Non         | Durée estimée en minutes (min : 1). |
| `notes`            | string  | Non         | Notes internes pour la visite (max 2000). |
| `status`           | string  | Non         | Statut initial : `scheduled`, `completed` ou `cancelled`. |
| `team_member_id`   | integer | Non         | Identifiant du technicien assigné à la visite. |

**Réponse (201) :** la visite terrain créée.

#### GET /api/v1/site-visits/{id}

Récupère une visite terrain avec les détails du chantier, du client et du technicien.

**Réponse :**

```json
{
  "data": {
    "id": 7,
    "job_id": 12,
    "customer_id": 1,
    "team_member_id": 2,
    "scheduled_at": "2026-03-20T09:00:00+01:00",
    "duration_minutes": 120,
    "status": "scheduled",
    "notes": "Le client sera présent dès 9h.",
    "created_at": "2026-03-01T11:00:00+01:00",
    "updated_at": "2026-03-01T11:00:00+01:00",
    "job": {
      "id": 12,
      "title": "Réparation plomberie salle de bain"
    },
    "customer": {
      "id": 1,
      "full_name": "Marie Dupont"
    },
    "team_member": {
      "id": 2,
      "name": "Jean Martin"
    }
  }
}
```

#### PUT /api/v1/site-visits/{id}

Met à jour une visite terrain. Envoyez uniquement les champs à modifier. Accepte `scheduled_at`, `duration_minutes`, `notes`, `status` et `team_member_id`.

#### DELETE /api/v1/site-visits/{id}

Supprime une visite terrain. Retourne `204 No Content`.

---

### Factures

Les factures utilisent un système de numérotation séquentielle immuable. Pour garantir l'intégrité de l'audit, les factures ne peuvent pas être modifiées ni supprimées via l'API.

#### GET /api/v1/invoices

Liste les factures de votre entreprise.

**Paramètres de requête :**

| Paramètre     | Type    | Description |
|---------------|---------|-------------|
| `from`        | string  | Date de création de début (`YYYY-MM-DD`). |
| `to`          | string  | Date de création de fin (`YYYY-MM-DD`). |
| `customer_id` | integer | Filtrer par client. |
| `paid`        | boolean | Filtrer par statut de paiement. |
| `per_page`    | integer | Résultats par page (défaut : 25, max : 100). |
| `page`        | integer | Numéro de page. |

**Réponse :**

```json
{
  "data": [
    {
      "id": 42,
      "invoice_number": "FA260200042",
      "customer_id": 1,
      "paid": true,
      "total_with_tax": 180.00,
      "notes": "Merci pour votre confiance !",
      "created_at": "2026-02-15T10:00:00+01:00",
      "updated_at": "2026-02-15T10:00:00+01:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 2,
    "per_page": 25,
    "total": 38
  }
}
```

#### GET /api/v1/invoices/{id}

Récupère une facture avec ses lignes et les coordonnées du client.

**Réponse :**

```json
{
  "data": {
    "id": 42,
    "invoice_number": "FA260200042",
    "customer_id": 1,
    "paid": true,
    "total_with_tax": 180.00,
    "notes": "Merci pour votre confiance !",
    "created_at": "2026-02-15T10:00:00+01:00",
    "updated_at": "2026-02-15T10:00:00+01:00",
    "customer": {
      "id": 1,
      "full_name": "Marie Dupont",
      "email": "marie@exemple.fr"
    },
    "lines": [
      {
        "id": 101,
        "item_id": 5,
        "description": "Réparation plomberie - salle de bain",
        "quantity": 1,
        "unit_price_with_tax": 180.00,
        "discount_percent": 0,
        "line_total_with_tax": 180.00
      }
    ]
  }
}
```

#### POST /api/v1/invoices

Crée une nouvelle facture. Le numéro de facture est attribué automatiquement.

**Corps de la requête :**

```json
{
  "customer_id": 1,
  "paid": false,
  "notes": "Merci pour votre confiance !",
  "lines": [
    {
      "item_id": 5,
      "description": "Réparation plomberie - salle de bain",
      "quantity": 1,
      "price_with_tax": 180.00,
      "discount": 0
    }
  ]
}
```

| Champ                    | Type    | Obligatoire | Description |
|--------------------------|---------|-------------|-------------|
| `customer_id`            | integer | Oui         | Identifiant du client. |
| `paid`                   | boolean | Non         | Facture déjà réglée (défaut : `false`). |
| `notes`                  | string  | Non         | Notes imprimées sur la facture (max 5000). |
| `lines`                  | array   | Non         | Tableau des lignes de facturation. |
| `lines[].item_id`        | integer | Non         | Identifiant de l'article du catalogue. |
| `lines[].description`    | string  | Non         | Description de la ligne (max 1000). |
| `lines[].quantity`       | number  | Oui*        | Quantité (obligatoire si `lines` est présent, min : 0.01). |
| `lines[].price_with_tax` | number  | Oui*        | Prix unitaire TTC (obligatoire si `lines` est présent, min : 0). |
| `lines[].discount`       | number  | Non         | Remise en pourcentage sur cette ligne (0-50). |

*Obligatoire uniquement lorsque le tableau `lines` est présent.

**Réponse (201) :** la facture créée au même format que `GET /api/v1/invoices/{id}`.

---

## Réponses d'erreur

L'API retourne des codes HTTP standards. Les réponses d'erreur incluent un corps JSON avec un champ `error` et, pour les erreurs de validation, un champ `messages`.

| Code | Signification |
|------|---------------|
| 401  | Non authentifié. Le jeton est absent ou invalide. |
| 403  | Accès refusé. Vous n'avez pas accès à cette ressource. |
| 404  | Ressource introuvable. |
| 422  | Erreur de validation. Consultez le champ `messages`. |
| 429  | Trop de requêtes. Limite de 60 requêtes par minute. |
| 500  | Erreur interne du serveur. |

**Exemple d'erreur de validation :**

```json
{
  "error": "Validation failed.",
  "messages": {
    "first_name": ["The first name field is required."],
    "email": ["The email must be a valid email address."]
  }
}
```

---

## Pagination

Tous les endpoints de liste retournent des résultats paginés avec un objet `meta` :

```json
{
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 25,
    "total": 118
  }
}
```

Utilisez les paramètres `page` et `per_page` pour naviguer dans les résultats.

---

## Premiers pas

1. Connectez-vous à votre espace d'administration Check-in ARTISAN.
2. Allez dans **Compte Check-in ARTISAN > Jetons API**.
3. Cliquez sur **Générer un jeton**, donnez-lui un nom et copiez le jeton affiché.
4. Utilisez ce jeton dans l'en-tête `Authorization: Bearer` de toutes vos requêtes authentifiées.
5. Testez avec une requête simple vers `/api/v1/company` pour vérifier que votre jeton fonctionne.

---

## Support

Pour toute question sur l'intégration de l'API, contactez-nous via la **[page Contact](/fr/contact)** ou consultez la documentation complète.
