# SDK

Le SDK **Abby Node.js, Bun & Deno** est la librairie officielle de l’API Abby. Il évite d’écrire vos requêtes HTTP à la main. Il ajoute du typage TypeScript et de la validation runtime.

* NPM : <https://www.npmjs.com/package/@abby-inc/node>
* GitHub : <https://github.com/abby-inc/abby-node>

### Quand l’utiliser

Utilisez le SDK si vous développez :

* Un backend Node.js.
* Un script Bun.
* Une app Deno.

Pour du no-code, utilisez Make.

### Prérequis

* Node.js `>= 18`, Bun `>= 1`, ou Deno `>= 2`.
* Une clé API Abby.

La création et la gestion de la clé est décrite dans [Authentification](/api/authentification.md).

{% hint style="warning" %}
Gardez la clé API côté serveur. Ne l’exposez jamais au navigateur. Ne la commitez jamais.
{% endhint %}

### Installation

{% tabs %}
{% tab title="npm" %}

```bash
npm install @abby-inc/node
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add @abby-inc/node
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm add @abby-inc/node
```

{% endtab %}

{% tab title="bun" %}

```bash
bun add @abby-inc/node
```

{% endtab %}

{% tab title="deno" %}

```typescript
import Abby from 'npm:@abby-inc/node';
```

{% endtab %}
{% endtabs %}

### Démarrage rapide

#### Initialisation

```typescript
import Abby from '@abby-inc/node';

const abby = new Abby('your_api_key');
```

#### Exemple simple

```typescript
import Abby from '@abby-inc/node';

const abby = new Abby('your_api_key');

async function main() {
  const { data: me } = await abby.company.getMe();
  console.log(`Welcome back, ${me.user.firstname}!`);

  const { data: contacts } = await abby.contact.retrieveContacts({
    query: { limit: 10 },
  });

  console.log(`Found ${contacts.docs.length} contacts.`);
}

main().catch(console.error);
```

### Services

Le SDK expose des services par domaine métier. La liste ci-dessous suit le README.

* `abby.company` : infos société et préférences.
* `abby.invoice` : factures.
* `abby.estimate` : devis.
* `abby.contact` : contacts (clients).
* `abby.organization` : organisations.
* `abby.billing` : utilitaires de facturation (PDF, emails).
* `abby.opportunity` : CRM et opportunités.
* `abby.asset` : immobilisations.
* `abby.advance` : acomptes.

Pour la doc API dans GitBook :

* [Clients](/api/clients.md)
* [Factures](/api/factures.md)
* [Livre des recettes](/api/livre-des-recettes.md)
* [Livre des achats](/api/livre-des-achats.md)

### Configuration

Vous pouvez passer des options au constructeur.

```typescript
import Abby from '@abby-inc/node';

const abby = new Abby('your_api_key', {
  baseUrl: 'https://api.app-abby.com',
  timeout: 30000,
  headers: {
    'X-Custom-Header': 'value',
  },
});
```

Options :

* `baseUrl` (défaut `https://api.app-abby.com`) : base URL de l’API.
* `timeout` (défaut `30000`) : timeout en millisecondes.
* `headers` : headers ajoutés à toutes les requêtes.
* `fetch` (défaut `globalThis.fetch`) : fetch custom (proxy, logs, tests).

### Fetch custom et proxy

Le SDK accepte un `fetch` custom. Ça sert pour un proxy, des logs, ou des tests.

Proxy avec `undici` :

```typescript
import Abby from '@abby-inc/node';
import { fetch as undiciFetch, ProxyAgent } from 'undici';

const proxyAgent = new ProxyAgent('http://proxy.example.com:8080');

const abby = new Abby('your_api_key', {
  fetch: (url, init) =>
    undiciFetch(url, {
      ...init,
      dispatcher: proxyAgent,
    }),
});
```

Logging simple :

```typescript
import Abby from '@abby-inc/node';

const abby = new Abby('your_api_key', {
  fetch: async (url, init) => {
    console.log(`[Abby SDK] ${init?.method ?? 'GET'} ${url}`);
    const start = Date.now();

    const response = await globalThis.fetch(url, init);

    console.log(`[Abby SDK] ${response.status} in ${Date.now() - start}ms`);
    return response;
  },
});
```

### Gestion des erreurs

Le SDK lève des erreurs en cas de réponse 4xx/5xx. Vous pouvez router par code HTTP.

```typescript
try {
  await abby.invoice.getInvoice({
    path: { invoiceId: 'inv_invalid' },
  });
} catch (error) {
  if (error.status === 404) {
    console.error('Invoice not found');
  } else if (error.status === 401) {
    console.error('Invalid API key');
  } else {
    console.error('Unexpected error:', error.message);
  }
}
```

Pour les détails, voir [Erreurs](/api/erreurs.md).

### Événements (listeners)

Vous pouvez écouter globalement erreurs et réponses. C’est utile pour du logging centralisé.

Écouter toutes les erreurs :

```typescript
import Abby from '@abby-inc/node';

const abby = new Abby('your_api_key');

abby.on('error', (error) => {
  console.error(`API Error: ${error.status} ${error.statusText}`);
  console.error(`URL: ${error.method} ${error.url}`);
  console.error(`Message: ${error.message}`);
  console.error(`Duration: ${error.duration}ms`);
});
```

Écouter toutes les réponses :

```typescript
abby.on('response', (response) => {
  console.log(`${response.method} ${response.url} - ${response.status} (${response.duration}ms)`);
});
```

Supprimer un listener :

```typescript
const errorHandler = (error) => console.error(error);

abby.on('error', errorHandler);
abby.off('error', errorHandler);
```

### Interceptors

Les interceptors hookent le cycle request/response.

```typescript
const client = abby.getClient();

client.interceptors.request.use((request) => {
  request.headers.set('X-Request-ID', crypto.randomUUID());
  return request;
});

client.interceptors.response.use((response) => {
  console.log(`API Response: ${response.status}`);
  return response;
});
```

### Requêtes “raw”

Utilisez le client HTTP si un endpoint manque. La clé API et les headers SDK sont ajoutés automatiquement.

```typescript
import Abby from '@abby-inc/node';

const abby = new Abby('your_api_key');
const client = abby.getClient();

const { data } = await client.get({
  url: '/v2/some/endpoint',
});

const { data: result } = await client.post({
  url: '/v2/some/endpoint',
  body: { field: 'value' },
});
```

### Validation (Zod)

Le SDK valide requêtes et réponses avec [Zod](https://zod.dev). Une `ZodError` est levée si ça ne matche pas le schéma.

```typescript
import Abby from '@abby-inc/node';
import { ZodError } from 'zod';

const abby = new Abby('your_api_key');

try {
  await abby.contact.createContact({ body: {} });
} catch (error) {
  if (error instanceof ZodError) {
    console.error('Validation failed:', error.errors);
  }
}
```

Vous pouvez aussi utiliser les schémas exportés :

```typescript
import { z } from 'zod';
import { zCreateContactDto, zReadContactDto } from '@abby-inc/node';

type CreateContactInput = z.infer<typeof zCreateContactDto>;
type Contact = z.infer<typeof zReadContactDto>;

const input = {
  firstname: 'John',
  lastname: 'Doe',
  email: 'john@example.com',
};

zCreateContactDto.parse(input);
```

### TypeScript

Le SDK est écrit en TypeScript. Il expose des types pour les DTOs.

```typescript
import Abby, { ReadMeDto } from '@abby-inc/node';

const abby = new Abby('your_api_key');

async function getCompanyData() {
  const { data }: { data: ReadMeDto } = await abby.company.getMe();
  return data;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.abby.fr/api/sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
