---
title: "Sources de compte"
description: "Relier et délier une source de données externe à un compte, par API."
canonical: https://developer.billabex.com/fr/guides/sources-de-compte/
lang: fr
alternate: https://developer.billabex.com/en/guides/sources/
last-updated: 2026-10-25
---

# Sources de compte

> Relier et délier une source de données externe à un compte, par API.

Source: https://developer.billabex.com/fr/guides/sources-de-compte/
Langue: Français (fr)
Version anglaise: https://developer.billabex.com/en/guides/sources/

Quand vous synchronisez des comptes depuis un système externe (ERP, CRM, plateforme de facturation), vous pouvez relier chaque compte Billabex à son enregistrement d'origine par une **référence de source**. Ce guide explique comment elles fonctionnent et comment les gérer par l'API.

## Qu'est-ce qu'une source ?

Une source est une référence qui relie un compte Billabex à un système externe. Elle dit à Billabex :

- **d'où** viennent les données du compte, par l'identifiant de votre intégration ;
- **à quel** enregistrement il correspond, par l'identifiant dans le système externe ;
- **quand** il a été synchronisé pour la dernière fois.

Quand un compte a une source, Billabex le considère comme géré de l'extérieur, ce qui change la façon dont il peut être modifié et supprimé.

### La source d'un compte et le `sourceId` d'un document sont deux choses différentes

Une organisation n'a pas *une* source de données. Elle peut détenir plusieurs connexions de connecteur à la fois (Odoo, Pennylane, Qonto, Sellsy, Stripe, Zoho Books) pendant que son équipe saisit des factures dans la webapp et que votre intégration en dépose d'autres par cette API.

La source décrite ici appartient à un **compte**. Les factures et les avoirs ne portent pas de référence de source, mais chacun peut porter un `sourceId` à plat : **votre** identifiant pour ce document dans **votre** système. Même mot, deux espaces de noms, deux portées :

| Champ             | Porté par              | Portée de l'unicité   | Posé par                               |
| ----------------- | ---------------------- | --------------------- | -------------------------------------- |
| `source.sourceId` | un compte              | par connexion         | `PUT /accounts/{accountId}/source`     |
| `sourceId`        | une facture ou un avoir | par organisation     | `POST /invoices`, `POST /credit-notes` |

Envoyez `sourceId` à la création d'un document et vous obtenez une poignée d'idempotence gratuite : une seconde création avec le même `sourceId` est refusée en `400` avec `app-invoicing.invoice.duplicate-source-id` (ou `app-invoicing.credit-note.duplicate-source-id`), au lieu de produire un doublon en silence après une réponse HTTP perdue. Récupérez le document avec `GET /invoices?filters=sourceId:is:VOTRE-ID`. La valeur est figée à la création, jamais modifiable ensuite, opaque pour Billabex, et **sensible à la casse** : `sourceId` n'accepte que les opérateurs de filtre `is`, `isAnyOf`, `isEmpty` et `isNotEmpty`, jamais `contains` ni `equals`.

Les numéros de documents sont uniques **par compte**, pas par organisation : deux de vos clients peuvent chacun avoir leur propre `AVKA0011527`, et les deux sont acceptés. Une recherche par numéro restreinte à un compte répond le document de ce compte ; une recherche par numéro sur toute une organisation peut répondre n'importe lequel des homonymes, alors passez le compte dès que vous le connaissez. Le rapprochement sur `sourceId` évite entièrement la question.

Quelques conséquences à intégrer :

- **Un compte sans source est parfaitement normal.** Cela signifie simplement qu'aucun connecteur ne le pilote. Ce n'est ni un enregistrement incomplet ni un enregistrement cassé.
- **La source d'un compte ne dit jamais d'où vient l'une de ses factures.** Chaque facture et chaque avoir porte son propre `channel`, posé une fois à la création et jamais modifié ensuite : `PublicApi` pour une création par cette API, `Manual` pour une saisie dans la webapp, `AdminApi` ou `Mcp` pour les autres points d'entrée programmatiques, ou le nom du connecteur pour un import par connecteur. Les documents créés avant que ces points d'entrée soient distingués portent la valeur historique `Api`. Lisez `channel` sur le document, pas `source` sur le compte.
- **Un document importé par un connecteur porte aussi un `connectionId`**, qui nomme la connexion exacte dont il vient. Il vaut `null` sur tout ce que vous créez, et sur les documents antérieurs à ce champ. Listez les factures d'une connexion avec `GET /invoices?filters=connectionId:is:ID-DE-CONNEXION`, et comptez celles de chaque connexion en un appel avec `GET /analytics/invoices-by-connection`.
- **Ne déduisez jamais « puis-je écrire ceci » de `channel` ni de `source`.** Chaque compte, facture et avoir porte un `readOnlyReason` : `null` signifie qu'il accepte les écritures, sinon il nomme le connecteur qui les écraserait. Il est renvoyé par les endpoints de ressource unique **et** par chaque élément de `GET /accounts`, `GET /invoices` et `GET /credit-notes` : paginer une liste vous dit donc déjà quelles lignes vous pouvez modifier ou supprimer. Une écriture tentée alors qu'il est renseigné échoue avec `app-invoicing.document.managed-action-forbidden`.
- **`source: null` seul ne signifie pas « jamais connecté ».** Un compte porte aussi `lastUnlinkedSource`, la source dont il a été détaché. Les deux à `null` signifient que le compte a été créé à la main ou par cette API ; `source: null` avec `lastUnlinkedSource` renseigné signifie que le lien vers un outil de facturation a été rompu, et donc que les chiffres ne suivent plus cet outil. Lisez les deux ensemble avant de considérer un compte comme géré manuellement.

## Propriétés d'une source

Une référence de source contient quatre propriétés :

| Propriété       | Type     | Description                                                        |
| --------------- | -------- | ------------------------------------------------------------------ |
| `connectionId`  | chaîne   | Identifiant de votre intégration, par exemple `my-erp-sync`        |
| `sourceId`      | chaîne   | Identifiant du compte dans votre système externe, par exemple `CUST-00123` |
| `connectorType` | chaîne   | Toujours `Custom` pour une source gérée par API                    |
| `lastUpdate`    | datetime | Date du dernier lien ou de la dernière mise à jour                 |

`connectionId` regroupe les comptes d'une même intégration. Utilisez une valeur cohérente pour tous les comptes venant du même système source.

`sourceId` identifie le compte de façon unique dans votre système externe. Il devrait correspondre à la clé primaire ou à l'identifiant unique de votre base source.

## Relier une source

Utilisez le **PUT** pour relier une source à un compte existant :

```
PUT /api/public/v1/accounts/{accountId}/source
```

Cet endpoint est **idempotent** : appelé avec la même source (mêmes `connectionId` et `sourceId`), il met simplement à jour la date `lastUpdate` au lieu de renvoyer une erreur.

### Requête

```javascript
const response = await fetch(
  'https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source',
  {
    method: 'PUT',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      connectionId: 'my-erp-integration',
      sourceId: 'CUST-00123',
      // Facultatif : préciser une date lastUpdate
      // lastUpdate: '2024-01-15T10:30:00.000Z',
    }),
  },
);

const account = await response.json();
```

### Avec cURL

```bash
curl -X PUT "https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "connectionId": "my-erp-integration",
    "sourceId": "CUST-00123"
  }'
```

### Corps de la requête

| Propriété      | Type     | Obligatoire | Description                                                    |
| -------------- | -------- | ----------- | -------------------------------------------------------------- |
| `connectionId` | chaîne   | oui         | Identifiant de votre intégration                               |
| `sourceId`     | chaîne   | oui         | Identifiant du compte dans votre système externe               |
| `lastUpdate`   | datetime | non         | Date de la dernière synchronisation, maintenant par défaut     |

### Réponse

L'endpoint renvoie le compte mis à jour, avec sa référence de source :

```json
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "fullName": "Acme Corporation",
  "source": {
    "connectionId": "my-erp-integration",
    "sourceId": "CUST-00123",
    "connectorType": "Custom",
    "lastUpdate": "2024-01-15T10:30:00.000Z"
  }
}
```

`connectorType` vaut toujours `Custom`. Si `lastUpdate` n'est pas fourni, il prend l'heure courante du serveur.

## Mettre à jour la date de synchronisation

Utilisez le **PATCH** pour ne mettre à jour que la date `lastUpdate` d'une source existante :

```
PATCH /api/public/v1/accounts/{accountId}/source
```

Pratique pour marquer un compte comme « récemment synchronisé » sans relier à nouveau toute la source.

### Requête

```javascript
const response = await fetch(
  'https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source',
  {
    method: 'PATCH',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      // Facultatif : préciser une date lastUpdate
      // Omise, elle prend l'heure courante
      lastUpdate: '2024-01-15T10:30:00.000Z',
    }),
  },
);

const account = await response.json();
```

### Avec cURL

```bash
# Mise à jour à l'heure courante
curl -X PATCH "https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

# Mise à jour à une date précise
curl -X PATCH "https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "lastUpdate": "2024-01-15T10:30:00.000Z"
  }'
```

### Corps de la requête

| Propriété    | Type     | Obligatoire | Description                                                   |
| ------------ | -------- | ----------- | ------------------------------------------------------------- |
| `lastUpdate` | datetime | non         | La nouvelle date de synchronisation, heure courante par défaut |

### Réponse

L'endpoint renvoie le compte mis à jour :

```json
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "fullName": "Acme Corporation",
  "source": {
    "connectionId": "my-erp-integration",
    "sourceId": "CUST-00123",
    "connectorType": "Custom",
    "lastUpdate": "2024-01-15T10:30:00.000Z"
  }
}
```

> **Note** : cet endpoint ne fonctionne que sur un compte qui a déjà une source. Sans source, vous recevez une erreur `400 Bad Request`.

## Créer un compte avec sa source

Vous pouvez aussi inclure la source à la création :

```javascript
const response = await fetch('https://next.billabex.com/api/public/v1/accounts', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    organizationId: 'YOUR_ORG_ID',
    fullName: 'Acme Corporation',
    currencyCode: 'EUR',
    billingAddress: {
      street: '123 rue Principale',
      city: 'Paris',
      postalCode: '75001',
      country: 'FR',
    },
    source: {
      connectionId: 'my-erp-integration',
      sourceId: 'CUST-00123',
    },
  }),
});
```

Le compte est créé et la source reliée en une seule requête.

## Délier une source

Pour retirer le lien de source d'un compte, utilisez le **DELETE** :

```
DELETE /api/public/v1/accounts/{accountId}/source
```

### Requête

```javascript
const response = await fetch(
  'https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source',
  {
    method: 'DELETE',
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  },
);

// Renvoie 204 No Content en cas de succès
```

### Avec cURL

```bash
curl -X DELETE "https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

L'endpoint renvoie `204 No Content` en cas de succès.

## Ce que cela implique dans Billabex

Relier une source à un compte a plusieurs conséquences.

### 1. Protection contre la suppression

Un compte avec une source ne peut pas être supprimé depuis l'interface Billabex. Il faut d'abord délier la source. Cela évite la suppression accidentelle de données synchronisées.

### 2. Exclusion désactivée dans l'interface

Un compte avec une source `Custom` ne peut pas être exclu depuis l'interface Billabex. La fonction d'exclusion est prévue pour les comptes pilotés par un connecteur, où l'utilisateur peut vouloir filtrer ce qui est synchronisé. Odoo v1 synchronise volontairement tous les comptes et n'expose pas encore ce filtre.

Pour un compte géré par API, c'est votre intégration qui décide directement quels comptes existent dans Billabex.

### 3. Statut orphelin après déliaison

Quand vous déliez une source, le compte devient « orphelin » : il n'a plus de lien avec aucun système externe. Il reste dans Billabex et peut alors être :

- supprimé manuellement depuis l'interface ;
- relié à une autre source par l'API ;
- géré de façon indépendante.

### 4. Seules les sources Custom se délient par API

L'endpoint de déliaison ne fonctionne que pour les comptes dont la source est `Custom`. Les comptes reliés par un connecteur Billabex (Odoo, Pennylane, Qonto, Sellsy, Stripe, Zoho Books) se gèrent depuis les réglages de leur connexion.

## Bonnes pratiques

### Des identifiants de connexion cohérents

Choisissez un `connectionId` parlant, qui identifie votre intégration :

```javascript
// Bien : l'intégration est clairement identifiée
connectionId: 'salesforce-billing-sync';
connectionId: 'netsuite-production';

// À éviter : trop générique ou incohérent
connectionId: 'sync';
connectionId: 'integration-1';
```

### Des identifiants de source stables

`sourceId` devrait être la clé primaire ou l'identifiant stable de votre système :

```javascript
// Bien : des identifiants stables
sourceId: 'CUST-00123'; // Numéro client
sourceId: 'acc_1234567890'; // Identifiant en base

// À éviter : des valeurs susceptibles de changer
sourceId: 'acme-corp'; // Nom de société, qui peut changer
```

### Relier avant de créer les données liées

Lors d'un import, reliez d'abord la source, puis créez les factures et les contacts :

1. créer ou mettre à jour le compte avec sa source ;
2. créer les contacts ;
3. créer les factures référençant le compte.

Toutes les données sont ainsi correctement associées à la référence du système externe.

### Gérer proprement une nouvelle liaison

Le PUT est idempotent. Appelé avec les mêmes `connectionId` et `sourceId` :

- la date `lastUpdate` est mise à jour ;
- aucune erreur n'est renvoyée.

Pour faire pointer la source vers un autre enregistrement externe, il faut d'abord délier la source courante, puis relier la nouvelle :

```javascript
// 1. Délier la source courante
await fetch('https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${accessToken}` },
});

// 2. Relier la nouvelle source
await fetch('https://next.billabex.com/api/public/v1/accounts/ACCOUNT_ID/source', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    connectionId: 'new-erp-integration',
    sourceId: 'NEW-CUST-456',
  }),
});
```

## Pour aller plus loin

- **[Opérations upsert](/fr/guides/upsert/)** : créer ou mettre à jour un contact en une requête
- **[Contacts](/fr/guides/contacts/)** : gérer les personnes rattachées à un compte
- **[Démarrage](/fr/guides/demarrage/)** : les bases de l'API et l'authentification
- **[Référence de l'API](/fr/reference-api/)** : documentation complète des endpoints

## Support

Une question sur les sources de compte ?
Écrivez-nous via le [formulaire de contact](https://www.billabex.com/fr/contactez-nous/).

---

Billabex developer portal. OpenAPI specification: https://developer.billabex.com/openapi.json.
Agent instructions: https://developer.billabex.com/llms.txt. Complete documentation: https://developer.billabex.com/llms-full.txt.
