---
seo_title: SDK Go de conversion de fichiers : client API sans dépendance
meta_desc: Le SDK Go officiel d'EnConvert pour Go 1.21+. Bibliothèque standard uniquement, zéro dépendance tierce, conversion typée et espace de noms web intelligence V2.
keywords: sdk go conversion de fichiers, convertir des fichiers en go, url vers pdf go, api scraping web go, docx vers pdf go, enconvert go sdk, bibliothèque golang html vers pdf, heic vers webp golang, api extraction markdown go, api capture d'écran de site golang, pipeline ingestion rag go, extraction de données structurées golang
---

# SDK Go de conversion de fichiers

`github.com/conversionapi/go-sdk` est le client EnConvert officiel pour Go 1.21 et plus récent. Il s'importe sous le package `enconvert` et ne porte aucune dépendance tierce : tout repose sur `net/http`, `encoding/json` et `mime/multipart`. Douze méthodes du client couvrent la conversion de fichiers, le rendu d'URL et les lots de site entier (DOCX vers PDF, HEIC vers WebP, URL vers PDF, URL vers Markdown), et l'espace de noms `client.V2` ajoute vingt-trois méthodes de web intelligence pour percevoir, découvrir, rechercher, extraire, ingérer et surveiller des pages. Chaque appel prend un `context.Context` en premier argument : l'annulation et les échéances restent donc entre vos mains.

<div class="alert alert-info">
<strong>Module :</strong> <code>github.com/conversionapi/go-sdk</code> · <strong>Package :</strong> <code>enconvert</code> · <strong>Source :</strong> <a href="https://github.com/conversionapi/go-sdk">conversionapi/go-sdk</a> · <strong>Go :</strong> 1.21+ · <strong>Dépendances :</strong> aucune
</div>

---

## Installation

```bash
go get github.com/conversionapi/go-sdk
```

Le chemin du module se termine par `go-sdk` mais le package s'appelle `enconvert` : importez-le donc sous un nom explicite, `import enconvert "github.com/conversionapi/go-sdk"`.

---

## Démarrage rapide

```go
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    enconvert "github.com/conversionapi/go-sdk"
)

func main() {
    client, err := enconvert.New(os.Getenv("ENCONVERT_API_KEY"))
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    result, err := client.ConvertURLToPDF(ctx, "https://example.com", enconvert.URLToPDFOptions{SaveTo: "page.pdf"})
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(result.Filename, result.PresignedURL)
}
```

`New` ne renvoie une erreur que lorsque la clé API est vide ; voir [Configuration](#configuration) pour les options fonctionnelles. Lire une page comme un agent devrait le faire, avec un score de qualité attaché, tient en un appel sur l'espace de noms V2 :

```go
op, err := client.V2.Perceive(ctx, "https://example.com", enconvert.PerceiveOptions{
    Outputs: []enconvert.PerceiveOutputName{enconvert.PerceiveOutputMarkdown},
})
fmt.Println(op.Outputs["markdown"].URL, *op.RenderQuality) // par ex. 0.93
```

Tous les extraits ci-dessous supposent un `client` et un `ctx` construits exactement comme ceci.

---

## Ce que le client expose

Douze méthodes sont accrochées à `*enconvert.Client` et mappées 1:1 sur des endpoints REST. Les options sont toujours passées par valeur de struct, jamais par pointeur : la valeur zéro (`enconvert.URLToPDFOptions{}`) signifie donc « tout par défaut », et les nombres et booléens facultatifs sont des champs pointeurs partout ; utilisez les helpers `enconvert.Int`, `enconvert.Bool`, `enconvert.Float64` et `enconvert.String` plutôt qu'une variable locale jetable.

| Méthode | Endpoint | Renvoie |
|--------|----------|---------|
| `ConvertURLToPDF(ctx, url, opts)` | `POST /v1/convert/url-to-pdf` | `ConversionResult` |
| `ConvertURLToScreenshot(ctx, url, opts)` | `POST /v1/convert/url-to-screenshot` | `ConversionResult` |
| `ConvertURLToMarkdown(ctx, url, opts)` | `POST /v1/convert/url-to-markdown` | `ConversionResult` |
| `ConvertImage(ctx, file, opts)` | `POST /v1/convert/{from}-to-{to}` | `ConversionResult` |
| `ConvertDocument(ctx, file, opts)` | `POST /v1/convert/{from}-to-{to}` | `ConversionResult` |
| `ConvertToMarkdown(ctx, file, opts)` | `POST /v1/convert/anything-to-markdown` | `ConversionResult` |
| `ConvertToPDF(ctx, file, opts)` | `POST /v1/convert/anything-to-pdf` | `ConversionResult` |
| `ConvertWebsiteToPDF(ctx, url, opts)` | `POST /v1/convert/website-to-pdf` | `BatchSubmission` |
| `ConvertWebsiteToScreenshot(ctx, url, opts)` | `POST /v1/convert/website-to-screenshot` | `BatchSubmission` |
| `GetJobStatus(ctx, jobID)` | `GET /v1/convert/status/{jobID}` | `JobStatus` |
| `GetBatchStatus(ctx, batchID)` | `GET /v1/convert/batch/{batchID}` | `BatchStatus` |
| `WaitForBatch(ctx, batchID, opts)` | `GET /v1/convert/batch/{batchID}` (interrogé) | `BatchStatus` |

`client.V2` contient vingt-trois méthodes de plus, réparties sur six groupes de capacités :

| Groupe | Méthodes | Chemin de base |
|-------|---------|-----------|
| Perceive | `Perceive`, `PerceiveDirect`, `GetPerceiveOperation`, `DownloadPerceiveArtifact`, `PerceiveBatch`, `GetPerceiveBatch` | `/v2/perceive` |
| Discover | `Discover` | `/v2/discover` |
| Lookup | `Lookup` | `/v2/lookup` |
| Distill | `Distill` | `/v2/distill` |
| Ingest | `Ingest`, `IngestFiles`, `GetIngestJob`, `ListIngestJobs`, `CancelIngestJob`, `RetryIngestWebhook`, `GetWebhookSecret`, `RotateWebhookSecret` | `/v2/ingest` |
| Watch | `CreateWatcher`, `ListWatchers`, `GetWatcher`, `GetWatcherSnapshots`, `UpdateWatcher`, `DeleteWatcher` | `/v2/watch` |

---

## Conversion de fichiers

Les téléversements acceptent n'importe quel `FileSource` : `enconvert.FilePath("report.docx")` pour un chemin sur le disque (le nom de base décide du format d'entrée et du type MIME), `enconvert.FileBytes(buf)` pour des octets bruts sans nom (téléversés sous `upload.bin`, `application/octet-stream`), ou `enconvert.FileInput{Data: buf, Filename: "report.docx"}` pour des octets bruts avec un nom de fichier explicite et un `ContentType` facultatif.

### ConvertURLToPDF

Rendez en PDF n'importe quelle URL accessible.

```go
result, err := client.ConvertURLToPDF(ctx, "https://example.com", enconvert.URLToPDFOptions{
    SinglePage:       enconvert.Bool(false),
    PDFOptions:       &enconvert.PDFOptions{PageSize: "A4", Orientation: "landscape"},
    URLRenderOptions: enconvert.URLRenderOptions{ViewportWidth: enconvert.Int(1440)},
    SaveTo:           "report.pdf",
})
```

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `SaveTo` | `string` | -- | Chemin local vers lequel écrire le PDF en flux. Les répertoires parents sont créés pour vous. |
| `SinglePage` | `*bool` | `true` | `true` produit une seule page continue. `false` pagine en utilisant `PDFOptions.PageSize`. |
| `PDFOptions` | `*PDFOptions` | -- | Format de page, orientation, marges, échelle, niveaux de gris, en-tête, pied de page. Voir [Options PDF](#options-pdf). |
| `ViewportWidth`, `ViewportHeight` | `*int` | `1920`, `1080` | Taille de la fenêtre du navigateur, en pixels. |
| `LoadMedia` | `*bool` | `true` | Attend les images et les vidéos avant la capture. |
| `EnableScroll` | `*bool` | `true` | Fait défiler de haut en bas pour déclencher les chargements différés. |
| `OutputFilename` | `string` | auto | Remplace le nom de fichier généré. |
| `Auth` | `*HTTPBasicAuth` | -- | Identifiants HTTP Basic pour les pages derrière une connexion. |
| `Cookies`, `Headers` | `[]BrowserCookie`, `map[string]string` | -- | Cookies injectés avant le rendu (50 maximum) et en-têtes de requête supplémentaires (20 maximum, les en-têtes saut par saut sont rejetés). |

Tout ce qui va de `ViewportWidth` vers le bas vit sur la struct embarquée `URLRenderOptions`, partagée par toutes les méthodes basées sur une URL.

<div class="alert alert-warning">
<strong>Ne combinez pas <code>Auth</code> avec un en-tête <code>Authorization</code>.</strong> L'API rejette le conflit plutôt que de deviner lequel vous vouliez.
</div>

### ConvertURLToScreenshot et ConvertURLToMarkdown

Capturez un PNG de n'importe quelle URL, ou extrayez du Markdown GitHub-Flavored propre avec un frontmatter YAML (titre, description, url, liens, images). Le convertisseur Markdown supprime la navigation, les pieds de page, les publicités et les scripts, et conserve le corps principal de l'article.

```go
shot, err := client.ConvertURLToScreenshot(ctx, "https://example.com", enconvert.URLToScreenshotOptions{
    URLRenderOptions: enconvert.URLRenderOptions{ViewportWidth: enconvert.Int(1440)},
    SaveTo:           "shot.png",
})

article, err := client.ConvertURLToMarkdown(ctx, "https://example.com/article",
    enconvert.URLToMarkdownOptions{SaveTo: "article.md"})
```

Les deux prennent les mêmes `URLRenderOptions` que `ConvertURLToPDF`, plus `SaveTo`. Ni l'une ni l'autre n'accepte `SinglePage` ou `PDFOptions`.

### ConvertImage

Convertissez entre `jpeg`, `png`, `svg`, `heic` et `webp` dans n'importe quel sens, ou rastérisez un PDF en JPEG.

```go
// Depuis un chemin
result, err := client.ConvertImage(ctx, enconvert.FilePath("photo.heic"),
    enconvert.ConvertImageOptions{OutputFormat: "webp", SaveTo: "photo.webp"})

// Depuis des octets déjà en mémoire
buf, _ := os.ReadFile("photo.heic")
result, err = client.ConvertImage(ctx, enconvert.FileInput{Data: buf, Filename: "photo.heic"},
    enconvert.ConvertImageOptions{OutputFormat: "webp", SaveTo: "photo.webp"})
```

| Option | Type | Obligatoire | Description |
|--------|------|----------|-------------|
| `OutputFormat` | `string` | Oui | `jpeg`, `png`, `svg`, `heic` ou `webp`. `jpg` est accepté comme alias de `jpeg`. |
| `SaveTo` | `string` | -- | Chemin local vers lequel écrire le résultat en flux. |
| `OutputFilename` | `string` | -- | Remplace le nom de fichier généré. |

Le format d'entrée vient de l'extension du nom de fichier (`.jpg`, `.jpeg`, `.png`, `.svg`, `.heic`, `.webp`, `.pdf`). Les paires non prises en charge échouent localement, avant tout appel réseau, avec une erreur listant ce qui est disponible :

```go
enconvert.ValidOutputsFor("pdf")  // []string{"jpeg"}
enconvert.ValidOutputsFor("json") // []string{"csv", "toml", "xml", "yaml"}
```

### ConvertDocument

Convertissez des documents et des formats de données. `OutputFormat` vaut `pdf` par défaut lorsqu'il est laissé vide.

```go
// docx vers pdf
_, err := client.ConvertDocument(ctx, enconvert.FilePath("report.docx"),
    enconvert.ConvertDocumentOptions{SaveTo: "report.pdf"})

// json vers yaml
_, err = client.ConvertDocument(ctx, enconvert.FilePath("data.json"),
    enconvert.ConvertDocumentOptions{OutputFormat: "yaml", SaveTo: "data.yaml"})
```

**Entrées prises en charge :** `.doc`, `.docx`, `.xls`, `.xlsx`, `.ppt`, `.pptx`, `.html`, `.htm`, `.odt`, `.ods`, `.odp`, `.ots`, `.pages`, `.numbers`, `.md`, `.markdown`, `.csv`, `.json`, `.xml`, `.yaml`, `.yml`, `.toml`.

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `OutputFormat` | `string` | `"pdf"` | Format cible. `yml`, `htm`, `md` et `jpg` sont normalisés vers leurs noms canoniques. |
| `SaveTo` | `string` | -- | Chemin local vers lequel écrire le résultat en flux. |
| `OutputFilename` | `string` | -- | Remplace le nom de fichier généré. |
| `PDFOptions` | `*PDFOptions` | -- | Mise en page. N'a de sens que lorsque la sortie est un PDF. |

Les 43 paires implémentées, exposées sous forme de table `enconvert.ImplementedConversions`, sont : `json` vers `csv`, `toml`, `xml`, `yaml` ; `xml` vers `csv`, `json` ; `yaml` vers `json` ; `csv` vers `json`, `xml` ; `toml` vers `json` ; `markdown` vers `html`, `pdf` ; `html` vers `pdf` ; `doc`, `excel`, `ppt`, `odt`, `ods`, `odp`, `ots`, `pages` et `numbers` vers `pdf` ; les 20 paires ordonnées entre `jpeg`, `png`, `svg`, `heic`, `webp` ; et `pdf` vers `jpeg`.

EPUB n'a pas de paire de document dédiée. Faites plutôt passer les fichiers `.epub` par `ConvertToPDF` ou `ConvertToMarkdown`.

### ConvertToMarkdown

Détectez automatiquement l'entrée côté serveur et récupérez du Markdown propre. C'est la brique d'ingestion RAG : PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT et MD, ainsi que les formats bureautiques anciens et ODF.

```go
_, err := client.ConvertToMarkdown(ctx, enconvert.FilePath("handbook.pdf"),
    enconvert.ConvertToMarkdownOptions{SaveTo: "handbook.md"})
```

`ConvertToMarkdownOptions` a deux champs, `SaveTo` et `OutputFilename`. Les images ne sont pas prises en charge par cet endpoint, et il n'y a aucune option PDF dessus. La sortie conserve la hiérarchie de titres du document, si bien qu'un découpeur sémantique peut segmenter sur les titres plutôt que sur un nombre arbitraire de caractères.

### ConvertToPDF

Détectez automatiquement l'entrée côté serveur et récupérez un PDF : bureautique, ODF, Pages, Numbers, RTF, CSV, HTML, Markdown, texte brut, images matricielles, SVG, EPUB, ou un PDF existant transmis tel quel pour normalisation.

```go
_, err := client.ConvertToPDF(ctx, enconvert.FilePath("slides.pptx"),
    enconvert.ConvertToPDFOptions{SaveTo: "slides.pdf"})

// Passthrough PDF, converti en niveaux de gris
_, err = client.ConvertToPDF(ctx, enconvert.FilePath("scan.pdf"), enconvert.ConvertToPDFOptions{
    PDFOptions: &enconvert.PDFOptions{Grayscale: enconvert.Bool(true)},
    SaveTo:     "scan-gray.pdf",
})
```

<div class="alert alert-warning">
<strong>Seul <code>PDFOptions.Grayscale</code> est pris en compte ici.</strong> Tous les autres champs de géométrie sont ignorés sur <code>anything-to-pdf</code>. Utilisez <code>ConvertDocument</code> ou <code>ConvertURLToPDF</code> quand vous avez besoin du format de page, de l'orientation, des marges, de l'échelle, des en-têtes ou des pieds de page.
</div>

`ConvertToPDFOptions` a trois champs : `SaveTo`, `OutputFilename` et `PDFOptions`.

### ConvertWebsiteToPDF et ConvertWebsiteToScreenshot

Découvrez chaque page d'un site, convertissez-les toutes en arrière-plan, et récupérez un seul ZIP. Les deux méthodes sont exclusivement asynchrones : elles renvoient un `BatchSubmission`, et vous interrogez avec `GetBatchStatus` ou bloquez avec `WaitForBatch`. Une clé API privée avec accès au crawl est requise.

```go
batch, err := client.ConvertWebsiteToPDF(ctx, "https://example.com", enconvert.WebsiteToPDFOptions{
    WebsiteConversionOptions: enconvert.WebsiteConversionOptions{CrawlMode: enconvert.CrawlModeSitemap},
})

status, err := client.WaitForBatch(ctx, batch.BatchID, enconvert.WaitForBatchOptions{SaveTo: "site.zip"})
fmt.Println(status.Completed, "of", status.Total, "pages converted")
```

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `CrawlMode` | `CrawlMode` | `auto` | `CrawlModeAuto`, `CrawlModeSitemap` (sitemap.xml uniquement), ou `CrawlModeFull` (sitemap plus crawl BFS). |
| `IncludePatterns` | `[]string` | -- | Ne crawle que les URL correspondant à ces motifs, en mode crawl complet. |
| `ExcludePatterns` | `[]string` | -- | Ignore les URL correspondant à ces motifs, en mode crawl complet. |
| `NotificationEmail` | `string` | propriétaire du projet | Adresse prévenue quand le lot se termine. |
| `CallbackURL` | `string` | -- | Webhook appelé en POST quand le lot se termine. |
| `SinglePage` | `*bool` | défaut serveur | PDF uniquement. Page continue ou paginée. |
| `PDFOptions` | `*PDFOptions` | -- | PDF uniquement. Appliqué à chaque page. |

Tout ce qui figure sur `URLRenderOptions` est également accepté ici, et n'est envoyé par page que lorsque vous le définissez. `WaitForBatchOptions` prend `Interval` (défaut 5 secondes), `Timeout` (défaut 30 minutes) et `SaveTo`. Dépasser le timeout renvoie un `*APIError` de statut `504` ; un lot terminé sans ZIP en renvoie un de statut `500`. `ConvertWebsiteToScreenshot` est identique, sans `SinglePage` ni `PDFOptions`, et produit un ZIP de PNG.

---

## Web intelligence (V2)

Chaque lecture V2 porte un score `RenderQuality` compris entre 0.0 et 1.0, exposé comme un `*float64` sur `PerceiveResult`, `DistillItem`, `WatcherSnapshot` et le résultat de téléchargement direct. Un score bas signifie que la page ne s'est pas rendue proprement : une page de défi, un mur de cookies, une coquille vide d'application monopage, une erreur HTTP. Le contenu revient tout de même, signalé, accompagné d'une table `Deductions` nommant chaque pénalité déclenchée et d'une tranche `Warnings` : une mauvaise lecture n'entre donc jamais discrètement dans le contexte de votre agent. Toutes les méthodes V2 exigent une clé API privée ; les clés publiques sont rejetées. Servez-vous du score comme d'une porte avant de faire confiance à quoi que ce soit :

```go
if op.RenderQuality != nil && *op.RenderQuality < 0.6 {
    log.Printf("low quality read of %s: %v", op.URL, op.Deductions)
}
```

### Perceive

Rendez une URL sous forme des artefacts que vous demandez. Synchrone, avec des URL d'artefacts signées pour 15 minutes.

```go
op, err := client.V2.Perceive(ctx, "https://example.com", enconvert.PerceiveOptions{
    Outputs:  []enconvert.PerceiveOutputName{enconvert.PerceiveOutputMarkdown, enconvert.PerceiveOutputStructured},
    Extract:  []enconvert.PerceiveExtractName{enconvert.PerceiveExtractTables, enconvert.PerceiveExtractMetadata},
    Viewport: &enconvert.PerceiveViewport{Width: enconvert.Int(1440)},
})
fmt.Println(op.OperationID, op.Outputs["markdown"].URL, op.Structured, op.ExtractionTier)

// Resigner les URL d'artefacts plus tard
again, err := client.V2.GetPerceiveOperation(ctx, op.OperationID)
```

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `Outputs` | `[]PerceiveOutputName` | `markdown`, `structured` | `markdown`, `html_cleaned`, `html_raw`, `screenshot`, `screenshot_full_page`, `pdf`, `links`, `images`, `structured`. |
| `Extract` | `[]PerceiveExtractName` | -- | `tables`, `prices`, `contacts`, `metadata`, `main_content`, `headings`, `structured_data`, `technologies`, `all`. |
| `Schema` | `map[string]any` | -- | Schéma JSON pour l'extraction structurée via le niveau LLM. |
| `WaitFor`, `WaitTimeoutMs` | `string`, `*int` | `30000` ms | Un sélecteur CSS, éventuellement préfixé `css:`, ou `js:<expr>`, et son budget (de 0 à 60000). |
| `JSCode` | `string` | -- | JavaScript exécuté après la navigation, 20000 caractères maximum. |
| `Viewport` | `*PerceiveViewport` | 1920 x 1080 | `Width` de 320 à 3840, `Height` de 240 à 2160. |
| `Headers`, `Cookies`, `Auth` | `map[string]string`, `[]BrowserCookie`, `*HTTPBasicAuth` | -- | En-têtes de requête, cookies injectés, identifiants HTTP Basic. |
| `CacheMode` | `PerceiveCacheMode` | `enabled` | `enabled` (cache d'une heure), `bypass`, `refresh`. |
| `PDFOptions` | `*PDFOptions` | -- | N'a de sens que lorsque `Outputs` inclut `pdf`. |
| `BlockResources` | `[]PerceiveResourceType` | -- | `image`, `media`, `font`, `stylesheet`, `script`, `xhr`, `fetch`, `websocket`, `manifest`, `other`. |
| `RespectRobots`, `Mobile` | `*bool` | défaut serveur | Respecte `robots.txt` ; émule un appareil mobile. |
| `OnlyMainContent` | `*bool` | `true` | Supprime la navigation, l'en-tête, le pied de page et les bandeaux de cookies de l'artefact markdown et de l'extrait `main_content`. Passez `false` pour la page entière. |
| `DirectDownload` | `*bool` | `false` | Diffuse les octets bruts au lieu d'une enveloppe JSON. Préférez `PerceiveDirect`. |

<div class="alert alert-warning">
<strong>Trois options sont déclarées mais pas encore actives.</strong> <code>ProxyURL</code>, <code>Geolocation</code> et <code>ActionChain</code> sont acceptées par la struct Go et sérialisées, mais le serveur répond actuellement <code>422</code> pour les trois. Laissez-les non définies.
</div>

Écrire un artefact unique directement sur le disque évite l'enveloppe JSON. `PerceiveDirect` valide localement que vous avez demandé exactement une sortie produisant un artefact :

```go
direct, err := client.V2.PerceiveDirect(ctx, "https://example.com", enconvert.PerceiveOptions{
    Outputs: []enconvert.PerceiveOutputName{enconvert.PerceiveOutputPDF},
})
os.WriteFile(direct.Filename, direct.Content, 0o644)

// Retélécharger un artefact stocké plus tard. Passez "" quand l'opération n'en a produit qu'un.
saved, err := client.V2.DownloadPerceiveArtifact(ctx, direct.OperationID, enconvert.PerceiveOutputPDF)
```

`PerceiveDirectResult` porte `Content`, `ContentType`, `Filename`, `OperationID`, `ObjectKey`, `CacheHit`, `RenderQuality`, `SourceStatusCode`, `ContentHash` et `WarningsCount`, tous lus dans les en-têtes de la réponse. Un `*APIError` `410` renvoyé par `DownloadPerceiveArtifact` signifie que l'artefact est sorti de sa fenêtre de rétention.

Les lots prennent jusqu'à 1000 URL avec un seul bloc d'options partagé. Les petits lots se terminent en ligne ; les plus gros reviennent en `queued`, alors interrogez `GetPerceiveBatch` jusqu'à ce que `Status` vaille `PerceiveBatchStatusCompleted` et lisez `Zip` ou `Items` :

```go
batch, err := client.V2.PerceiveBatch(ctx, []string{"https://a.example", "https://b.example"},
    enconvert.PerceiveBatchOptions{OutputMode: enconvert.PerceiveBatchOutputZip})
done, err := client.V2.GetPerceiveBatch(ctx, batch.JobID)
```

`OutputMode` vaut `PerceiveBatchOutputManifest` (défaut) ou `PerceiveBatchOutputZip`. `DirectDownload` est rejeté avec un `422` sur les lots.

### Discover

Énumérez les URL d'un site depuis son sitemap, un crawl HTTP, ou les deux. Aucun navigateur n'est démarré : c'est donc rapide et peu coûteux.

```go
found, err := client.V2.Discover(ctx, "https://example.com", enconvert.DiscoverOptions{
    Mode: enconvert.DiscoverModeHybrid, MaxURLs: enconvert.Int(200), ExcludePatterns: []string{"/tag/"},
})
fmt.Println(found.Total, found.Truncated, found.Sources)
```

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `Mode` | `DiscoverMode` | `hybrid` | `DiscoverModeSitemap`, `DiscoverModeCrawl`, ou `DiscoverModeHybrid` (sitemap plus crawl HTTP). |
| `MaxURLs`, `MaxDepth` | `*int` | `100`, `2` | De 1 à 1000 URL, profondeur de crawl de 1 à 5. |
| `IncludePatterns`, `ExcludePatterns` | `[]string` | -- | Liste d'autorisation par regex, puis liste de refus, sémantique `re.search`, 50 entrées maximum chacune. |
| `SameDomainOnly` | `*bool` | `true` | Reste sur le domaine de l'URL de départ. |
| `RespectRobots` | `*bool` | défaut serveur | Respecte `robots.txt`. |

`DiscoverResult` vous donne `URL`, `Mode`, `Total`, `URLs`, `PagesCrawled`, `Truncated`, `RobotsRespected`, `Sources` (décomptes bruts par source avant déduplication) et `Warnings`.

### Lookup

Recherche web catégorisée, avec rendu optionnel des meilleurs résultats dans le même aller-retour.

```go
search, err := client.V2.Lookup(ctx, "best static site generators", enconvert.LookupOptions{
    Category: enconvert.LookupCategoryWeb, NumResults: enconvert.Int(10), PerceiveTop: enconvert.Int(3),
})
for _, hit := range search.Results {
    fmt.Println(hit.Position, hit.Title, hit.URL)
    if hit.Perceive != nil {
        fmt.Println(hit.Perceive.Outputs["markdown"].URL)
    }
}
```

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `Category` | `LookupCategory` | `web` | `web`, `news`, `images`, `scholar`, `patents`, `maps`. |
| `Country`, `Locale` | `string` | -- | Code pays Google `gl` (`us`, `in`) et langue d'interface `hl` (`en`). |
| `TimeFilter` | `LookupTimeFilter` | -- | `hour`, `day`, `week`, `month`, `year`. |
| `NumResults`, `Page` | `*int` | `10`, `1` | De 1 à 100 résultats, page de 1 à 10. |
| `Location` | `string` | -- | Localisation en texte libre, par exemple `Austin, Texas`. |
| `Autocorrect` | `*bool` | `true` | Laisse le fournisseur corriger les fautes de frappe de la requête. |
| `PerceiveTop` | `*int` | `0` | De 0 à 10. Lance un rendu navigateur complet des N premières URL de résultats et attache chaque `PerceiveResult` en ligne. |

`LookupResult` porte également `AnswerBox`, `KnowledgeGraph`, `PerceiveOperationIDs` et `Warnings`.

### Distill

Extraction structurée pilotée par schéma. Fournissez exactement l'un de `URLs` (50 maximum) ou `DiscoverFrom` ; `Schema` est toujours obligatoire. Les deux règles sont vérifiées localement avant qu'une requête ne parte.

```go
extraction, err := client.V2.Distill(ctx, enconvert.DistillOptions{
    URLs:   []string{"https://example.com/pricing"},
    Schema: map[string]any{"plans": "list of plan names with monthly prices"},
    CSSSchema: &enconvert.CSSSchema{
        BaseSelector: ".plan-card",
        Fields: []enconvert.CSSField{
            {Name: "name", Type: enconvert.CSSFieldText, Selector: "h3"},
            {Name: "price", Type: enconvert.CSSFieldText, Selector: ".price"},
        },
    },
})
first := extraction.Results[0]
fmt.Println(first.Data, first.ExtractionTier, first.FieldsFromCSS, first.FieldsFromLLM)
```

Le `CSSSchema` facultatif s'exécute en premier et répond à tout ce qu'il peut avec de simples sélecteurs ; seuls les champs qu'il manque escaladent vers le niveau LLM, et `ExtractionTier` indique quels niveaux ont réellement répondu (`css`, `llm`, `mixed` ou `none`). `CSSField.Type` vaut `text`, `attribute`, `html`, `regex`, `nested`, `list` ou `nested_list`, imbriqué jusqu'à 5 niveaux de profondeur.

Remplacez `URLs` par `DiscoverFrom` pour découvrir puis extraire en un seul appel. `DistillDiscoverFrom` prend `URL`, `Mode` (défaut `hybrid`) et `MaxPages` (de 1 à 50, défaut 10, plafonnant à la fois la découverte et l'extraction) :

```go
_, err = client.V2.Distill(ctx, enconvert.DistillOptions{
    DiscoverFrom: &enconvert.DistillDiscoverFrom{URL: "https://example.com", MaxPages: enconvert.Int(10)},
    Schema:       map[string]any{"title": "page title", "summary": "one-line summary"},
})
```

### Ingest

Transformez un site, une liste d'URL, ou une pile de documents téléversés en JSONL découpé et prêt pour le RAG. Toujours asynchrone.

```go
job, err := client.V2.Ingest(ctx, enconvert.IngestOptions{
    Mode:       enconvert.IngestModeSitemap,
    URL:        "https://docs.example.com",
    MaxPages:   enconvert.Int(100),
    Chunk:      &enconvert.IngestChunkOptions{MaxWords: enconvert.Int(512), SentenceOverlap: enconvert.Int(1)},
    WebhookURL: "https://my.app/hooks/enconvert",
})

status, err := client.V2.GetIngestJob(ctx, job.JobID)
if status.Status == enconvert.IngestStatusCompleted {
    fmt.Println(status.TotalChunks, status.OutputURL)
}
```

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `Mode` | `IngestMode` | `urls` | `IngestModeURLs`, `IngestModeSitemap`, `IngestModeCrawl`, `IngestModeFiles`. |
| `URL` | `string` | -- | URL de départ. Obligatoire pour `sitemap` et `crawl`, interdite pour `urls`. |
| `URLs` | `[]string` | -- | URL explicites, 1000 maximum. Obligatoire pour `urls`, interdite sinon. |
| `MaxPages`, `MaxDepth` | `*int` | `50`, `2` | Plafond de découverte de 1 à 1000 pour `sitemap` et `crawl`, profondeur de 1 à 5. |
| `SameDomainOnly` | `*bool` | `true` | Reste sur le domaine de l'URL de départ. |
| `IncludePatterns`, `ExcludePatterns` | `[]string` | -- | Liste d'autorisation par regex, puis liste de refus. |
| `RespectRobots` | `*bool` | défaut serveur | Respecte `robots.txt`. |
| `WaitFor`, `WaitTimeoutMs` | `string`, `*int` | `30000` ms | Sélecteur ou expression `js:` attendu par page, et son budget (de 0 à 60000). |
| `Chunk` | `*IngestChunkOptions` | -- | `MaxWords` de 32 à 4000, défaut 512. `SentenceOverlap` de 0 à 10, défaut 1. |
| `WebhookURL` | `string` | -- | Webhook de fin, signé en HMAC. |

Les règles de mode et d'URL ci-dessus sont appliquées côté client : `Ingest` renvoie une erreur Go ordinaire, sans aller-retour API, si vous envoyez `URLs` avec `Mode: IngestModeSitemap`.

Les fichiers téléversés passent par le même pipeline et le même cycle de vie de tâche :

```go
fileJob, err := client.V2.IngestFiles(ctx,
    []enconvert.FileSource{enconvert.FilePath("handbook.pdf"), enconvert.FilePath("notes.docx")},
    enconvert.IngestFilesOptions{Chunk: &enconvert.IngestChunkOptions{MaxWords: enconvert.Int(512)}})
```

PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT et MD, ainsi que les fichiers bureautiques anciens ou ODF sont acceptés ; au moins un fichier est requis. Gestion des tâches et plomberie des webhooks :

```go
list, err := client.V2.ListIngestJobs(ctx, enconvert.V2ListOptions{Limit: enconvert.Int(20)})
canceled, err := client.V2.CancelIngestJob(ctx, job.JobID) // idempotent
secret, err := client.V2.GetWebhookSecret(ctx)             // Secret, SignatureHeader, SignatureScheme, ...
rotated, err := client.V2.RotateWebhookSecret(ctx)         // les anciennes signatures cessent aussitôt d'être valides
retry, err := client.V2.RetryIngestWebhook(ctx, job.JobID)
```

`RetryIngestWebhook` répond `409` quand la tâche n'est pas terminée et `400` quand elle n'a aucun webhook configuré. `V2ListOptions` prend `Skip` et `Limit` (de 1 à 100, défaut 20).

### Watch

Refaites le rendu d'une page à une cadence fixe et faites-vous prévenir quand elle change.

```go
watcher, err := client.V2.CreateWatcher(ctx, "https://example.com/pricing", enconvert.WatchCreateOptions{
    FrequencyMinutes: enconvert.Int(60),
    DiffMode:         enconvert.WatchDiffAuto,
    WebhookURL:       "https://my.app/hooks/changes",
})

history, err := client.V2.GetWatcherSnapshots(ctx, watcher.WatcherID, enconvert.SnapshotListOptions{Limit: enconvert.Int(10)})
for _, snap := range history.Snapshots {
    fmt.Println(snap.CheckedAt, snap.HasChanges, snap.ChangeCount, snap.Changes)
}
```

| Option | Type | Défaut | Description |
|--------|------|---------|-------------|
| `FrequencyMinutes` | `*int` | `60` | De 60 à 43200. Le plancher horaire est strict. |
| `DiffMode` | `WatchDiffMode` | `auto` | `WatchDiffAuto`, `WatchDiffText`, `WatchDiffStructured`, `WatchDiffTables`, `WatchDiffMetadata`. |
| `TrackFields` | `map[string]any` | -- | Sous-ensemble de champs ou de sélecteurs remis au moteur de diff. |
| `WebhookURL`, `NotifyEmail` | `string`, `*bool` | --, `true` | Webhook de changement signé en HMAC, et choix d'envoyer ou non un e-mail au propriétaire du projet. |

```go
// Un pointeur vers la chaîne vide efface le webhook ; nil le laisse tel quel.
_, err = client.V2.UpdateWatcher(ctx, watcher.WatcherID, enconvert.WatcherUpdate{
    Status: enconvert.WatcherStatusPaused, WebhookURL: enconvert.String(""),
})
_, err = client.V2.DeleteWatcher(ctx, watcher.WatcherID) // suppression douce, idempotente
```

`UpdateWatcher` exige au moins un champ et renvoie une erreur Go ordinaire si vous lui remettez une struct vide. `Status` n'accepte que `WatcherStatusActive` ou `WatcherStatusPaused` ; la suppression passe par `DeleteWatcher`, qui renvoie l'observateur marqué supprimé avec le statut `deleted`. `ListWatchers` et `GetWatcher` complètent le groupe.

<div class="alert alert-warning">
<strong>Les diffs d'instantanés contiennent du contenu de page non fiable.</strong> <code>WatcherSnapshot.Changes</code> est une tranche de tables brutes extraites de la page surveillée. Échappez les valeurs avant de les afficher où que ce soit.
</div>

---

## Options PDF

`PDFOptions` est partagé par `ConvertURLToPDF`, `ConvertDocument`, `ConvertWebsiteToPDF`, `PerceiveOptions`, et (pour `Grayscale` uniquement) `ConvertToPDF`. Seuls les champs que vous définissez sont envoyés.

```go
opts := &enconvert.PDFOptions{
    PageSize:    "A4",
    Orientation: "landscape",
    Margins:     &enconvert.PDFMargins{Top: enconvert.Float64(10), Bottom: enconvert.Float64(10)},
    Scale:       enconvert.Float64(0.9),
    Footer:      &enconvert.PDFHeaderFooter{Content: "Confidential", Height: enconvert.Float64(20)},
}
```

| Champ | Type | Description |
|-------|------|-------------|
| `PageSize` | `string` | `"A4"`, `"A3"`, `"Letter"`, `"Legal"`, et compagnie. |
| `PageWidth`, `PageHeight` | `*float64` | Définissez les deux ensemble pour remplacer `PageSize`. |
| `Orientation` | `string` | `"portrait"` ou `"landscape"`. Portrait par défaut. |
| `Margins` | `*PDFMargins` | `Top`, `Bottom`, `Left`, `Right`, chacun un `*float64` en points. Les quatre sont facultatifs. |
| `Scale` | `*float64` | Échelle de rendu, par exemple `0.9` pour 90 %. |
| `Grayscale` | `*bool` | Post-traite le PDF en niveaux de gris. |
| `Header`, `Footer` | `*PDFHeaderFooter` | Chacun a `Content` (2000 caractères maximum) et `Height`. |

---

## Gestion des erreurs

Go n'a pas de classes d'exception : chaque échec d'API est donc un unique type concret, `*enconvert.APIError`, accompagné de trois prédicats. `Error()` s'affiche sous la forme `"[<status>] <message>"`.

```go
result, err := client.ConvertURLToPDF(ctx, "https://example.com", enconvert.URLToPDFOptions{})
switch {
case err == nil:
    fmt.Println(result.PresignedURL)
case enconvert.IsAuthenticationError(err):
    log.Println("invalid or missing API key")
case enconvert.IsRateLimitError(err):
    log.Println("too many requests, back off and retry")
case enconvert.IsQuotaError(err):
    log.Println("request rejected with 402")
default:
    var apiErr *enconvert.APIError
    if errors.As(err, &apiErr) {
        log.Printf("api error [%d]: %s", apiErr.StatusCode, apiErr.Message)
    } else {
        log.Println(err) // échec réseau, annulation du contexte, validation locale
    }
}
```

| Vérification | Levée sur | Code de statut |
|-------|-----------|-------------|
| `IsAuthenticationError(err)` | Clé invalide, manquante ou révoquée | `401`, `403` (enregistrés tous deux comme `401`) |
| `IsQuotaError(err)` | Toute réponse à laquelle l'API répond `402` | `402` |
| `IsRateLimitError(err)` | Limite de débit dépassée | `429` |
| `errors.As(err, &apiErr)` | Toute autre 4xx ou 5xx | le code réel |

Les erreurs qui n'atteignent jamais le réseau, comme une paire de conversion non prise en charge, un appel `Distill` avec à la fois `URLs` et `DiscoverFrom`, ou un appel `PerceiveDirect` demandant deux artefacts, reviennent sous forme de valeurs `error` ordinaires issues de `errors.New` ou `fmt.Errorf`, pas de `*APIError`. Les codes de réponse sont catalogués dans la [référence des codes d'erreur](/fr/docs/error-codes).

---

## Récupération après timeout

Les rendus d'URL longs et les conversions de documents volumineux peuvent survivre au plafond de 60 à 120 secondes d'un reverse proxy, même quand la tâche se termine correctement côté serveur. Le SDK s'en sort par interrogation, sans une ligne de code de votre part :

1. Avant chaque conversion de fichier unique et d'URL unique, le client génère un UUIDv4 et l'envoie comme `job_id`.
2. Si cette requête revient avec un code `>= 500`, le client bascule discrètement sur `GET /v1/convert/status/{job_id}`, en interrogeant toutes les 3 secondes.
3. Sur `success` il renvoie le résultat. Sur `failed` il renvoie un `*APIError` de statut `500` avec le message du serveur.
4. L'échéance d'interrogation est de 5 minutes, après quoi vous obtenez un `*APIError` de statut `504` et de message `Conversion timed out`.

`ConversionResult.JobID` est toujours renseigné, même quand le chemin synchrone a réussi et que la réponse l'a omis : vous pouvez donc le remettre vous-même à `GetJobStatus` :

```go
status, err := client.GetJobStatus(ctx, result.JobID)
switch status.Status {
case enconvert.JobStatusSuccess:
    fmt.Println(status.PresignedURL)
case enconvert.JobStatusFailed:
    log.Println(status.Error)
}
```

<div class="alert alert-info">
<strong>Les lots de site se retirent volontairement de ce mécanisme.</strong> <code>ConvertWebsiteToPDF</code> et <code>ConvertWebsiteToScreenshot</code> n'ont aucune ligne de tâche propre à interroger : une 5xx à cet endroit remonte donc immédiatement au lieu d'être réessayée. Les méthodes V2 n'utilisent pas non plus le repli par tâche. L'interrogation se déroule à l'intérieur du <code>context.Context</code> que vous passez, si bien qu'annuler le contexte interrompt l'attente sur-le-champ.
</div>

---

## Configuration

```go
client, err := enconvert.New(os.Getenv("ENCONVERT_API_KEY"),
    enconvert.WithTimeout(300*time.Second),
    enconvert.WithBaseURL("https://api.enconvert.com"),
)
```

| Entrée du constructeur | Type | Défaut | Description |
|-------------------|------|---------|-------------|
| `apiKey` (premier argument) | `string` | obligatoire | Clé API privée. `New` renvoie une erreur lorsqu'elle est vide. |
| `WithTimeout(d)` | `time.Duration` | `300 * time.Second` | Définit `Timeout` sur le `*http.Client` interne, téléchargements compris. |
| `WithBaseURL(u)` | `string` | `https://api.enconvert.com` | Surcharge pour une passerelle auto-hébergée. Les barres obliques finales sont supprimées. |

Les échéances par appel viennent se superposer au timeout du client via le contexte : enveloppez-le avec `context.WithTimeout(context.Background(), 30*time.Second)` et passez-le en premier argument.

<div class="alert alert-warning">
<strong>N'écrivez jamais la clé API en dur.</strong> Lisez-la depuis une variable d'environnement ou votre gestionnaire de secrets, et gardez-la sur le serveur. Quiconque détient votre clé privée peut lancer des conversions sur votre projet.
</div>

Le client peut être partagé entre goroutines sans risque : il détient un `*http.Client` et aucun état mutable par requête. Construisez-en un au démarrage et réutilisez-le. Voir [authentification](/fr/docs/authentication) pour les types de clés et leur rotation.

---

## Forme du résultat

Les conversions de fichier unique et d'URL unique renvoient un `ConversionResult` :

```go
type ConversionResult struct {
    PresignedURL          string   // URL de téléchargement signée pour la sortie
    ObjectKey             string   // clé de l'objet de stockage
    Filename              string   // nom de fichier côté serveur
    FileSize              *int64   // octets, nil quand l'API l'omet
    ConversionTimeSeconds *float64 // nil quand l'API l'omet
    JobID                 string   // toujours défini par le client
}
```

Les URL pré-signées sont de courte durée de vie. Passez `SaveTo` pour que le SDK écrive les octets sur le disque pour vous, ou récupérez l'URL vous-même et stockez le fichier dans votre propre bucket si vous avez besoin d'un accès à long terme. Le téléchargement ne transporte volontairement pas votre clé API, puisqu'une URL pré-signée s'authentifie d'elle-même et que transmettre la clé à un hôte de stockage la ferait fuiter.

Les artefacts V2 arrivent sous forme de valeurs `V2OutputArtifact` indexées par nom de sortie, portant chacune `URL` (pré-signée pour 15 minutes et resignée à chaque GET de statut), `ObjectKey`, `SizeBytes`, `ContentType` et `ExpiresIn` (900 secondes par défaut). `PerceiveResult` les enveloppe avec les métadonnées d'honnêteté : `RenderQuality`, `StatusCode`, `Deductions`, `CacheHit`, `Warnings`, `ContentHash`, `URLFinal`, `Structured`, `ExtractionTier`, `Tokens`, `CostCents`, `DurationMs` et `OptionsEcho`, qui renvoie en écho les options réellement prises en compte par le serveur, avec les secrets réduits à des booléens.

---

## Source et tickets

- **Module et source :** [github.com/conversionapi/go-sdk](https://github.com/conversionapi/go-sdk)
- **Version :** exposée à l'exécution sous la constante `enconvert.Version`
- **Licence :** MIT, aucune dépendance tierce

Lectures associées : [tous les SDK](/fr/docs/sdks), [vue d'ensemble V2](/fr/docs/v2-overview), [perceive](/fr/docs/v2-perceive), [discover](/fr/docs/v2-discover), [lookup](/fr/docs/v2-lookup), [distill](/fr/docs/v2-distill), [ingest](/fr/docs/v2-ingest), [watch](/fr/docs/v2-watch), [vue d'ensemble des endpoints](/fr/docs/endpoints-overview), [paramètres et options](/fr/docs/parameters-options), et votre [tableau de bord](/fr/dashboard) pour les clés.

---

## Questions fréquentes

### Comment convertir des fichiers en Go ?

Lancez `go get github.com/conversionapi/go-sdk`, construisez un client avec `enconvert.New(os.Getenv("ENCONVERT_API_KEY"))`, puis appelez une méthode typée comme `ConvertDocument`, `ConvertImage` ou `ConvertURLToPDF`. Passez `SaveTo` dans la struct d'options et le SDK écrit le fichier terminé en flux directement vers ce chemin, en créant les répertoires parents si nécessaire.

### Comment convertir une URL en PDF en Go ?

Appelez `client.ConvertURLToPDF(ctx, url, enconvert.URLToPDFOptions{SaveTo: "page.pdf"})`. Définissez `SinglePage: enconvert.Bool(false)` pour paginer au lieu de produire une seule page continue, et passez `PDFOptions` pour le format de page, l'orientation, les marges, l'échelle, les niveaux de gris, les en-têtes et les pieds de page.

### Comment convertir du DOCX en PDF en Go ?

`client.ConvertDocument(ctx, enconvert.FilePath("report.docx"), enconvert.ConvertDocumentOptions{SaveTo: "report.pdf"})`. Le format de sortie vaut `pdf` par défaut : vous pouvez donc laisser `OutputFormat` vide. La même méthode gère les entrées XLSX, PPTX, ODT, ODS, ODP, OTS, Pages, Numbers, HTML, Markdown, CSV, JSON, XML, YAML et TOML.

### Comment convertir du HEIC en WebP en Go ?

`client.ConvertImage(ctx, enconvert.FilePath("photo.heic"), enconvert.ConvertImageOptions{OutputFormat: "webp", SaveTo: "photo.webp"})`. Le format d'entrée est lu dans l'extension du nom de fichier, et les 20 paires ordonnées entre `jpeg`, `png`, `svg`, `heic` et `webp` fonctionnent de la même façon. Les paires non prises en charge échouent localement avant l'envoi de toute requête.

### Le SDK Go entraîne-t-il des dépendances tierces ?

Non. `go.mod` déclare le module et un plancher Go 1.21, et rien d'autre. Le client est construit sur `net/http`, `encoding/json`, `mime/multipart` et `crypto/rand` de la bibliothèque standard : il n'ajoute donc aucune chaîne d'approvisionnement transitive à votre build.

### Comment récupérer une page web en Markdown propre avec Go ?

Deux possibilités. `client.ConvertURLToMarkdown` renvoie du Markdown GitHub-Flavored avec frontmatter YAML et constitue le chemin le plus simple. `client.V2.Perceive` avec `Outputs: []enconvert.PerceiveOutputName{enconvert.PerceiveOutputMarkdown}` vous donne le même Markdown plus un score `RenderQuality`, des `Deductions`, des `Warnings`, et la possibilité d'ajouter des captures d'écran, des liens ou une extraction structurée dans le même rendu.

### Que signifie la qualité de rendu et pourquoi faut-il la vérifier ?

`RenderQuality` est un `*float64` de 0.0 à 1.0 attaché à chaque lecture V2. Il baisse quand la page ne s'est pas rendue honnêtement : un défi anti-bot, un mur de connexion, un bandeau de cookies au-dessus d'une coquille vide, ou un statut HTTP d'erreur. Le contenu est tout de même renvoyé plutôt qu'avalé : vérifiez donc le score (et la table `Deductions` qui nomme chaque pénalité) avant de donner le texte à un modèle.

### Comment définir un timeout par requête ou annuler une conversion en Go ?

Chaque méthode prend un `context.Context` en premier argument. Enveloppez-le avec `context.WithTimeout` ou `context.WithCancel` pour un contrôle par appel ; `WithTimeout` sur le constructeur définit le timeout du client HTTP de base pour tous les appels, y compris le téléchargement d'un fichier `SaveTo`.

### Que se passe-t-il quand une conversion longue atteint le timeout du proxy ?

Le SDK envoie un `job_id` généré par le client avec chaque conversion de fichier unique et d'URL unique. Si la requête renvoie un code `>= 500`, il interroge `GET /v1/convert/status/{job_id}` toutes les 3 secondes pendant un maximum de 5 minutes, en renvoyant le résultat sur `success` et un `*APIError` sur `failed`. Dépasser l'échéance donne un `*APIError` de statut `504`. Les soumissions de lots de sites sautent volontairement ce repli.

### Puis-je livrer le SDK Go à l'intérieur d'un client desktop ou mobile ?

Non. Il s'authentifie avec une clé API privée, et les endpoints V2 rejettent purement et simplement les clés publiques. Gardez le client sur un serveur que vous contrôlez et laissez votre application dialoguer avec celui-ci. Voir [authentification](/fr/docs/authentication) pour le modèle de clés.

### Le client Go peut-il être utilisé depuis plusieurs goroutines ?

Oui. `*enconvert.Client` enveloppe un seul `*http.Client` et ne conserve aucun état mutable par requête : construisez-en un au démarrage et partagez-le partout.
