---
title: Démarrage rapide
description: Votre premier paiement crypto de test avec Coinetic en 15 minutes : clé API sandbox, création de facture, redirection et webhook.
url: https://coinetic.money/fr/docs/quickstart/
lang: fr
---

# Démarrage rapide

Un premier paiement en sandbox en 15 minutes. Il vous faut un serveur Node.js, PHP, Python ou Go : les exemples couvrent les quatre.

> **Résultat attendu.** Votre site crée une facture, le client paie sur la page Coinetic (en sandbox, d’un simple clic), votre serveur reçoit le webhook et livre la commande une seule et unique fois.

## 1. Obtenez vos clés sandbox

- Inscrivez-vous sur le [tableau de bord sandbox](https://sandbox.coinetic.money/merchant) et activez la 2FA.
- « Clés et webhooks » → « Créer une clé » : conservez le `key_id` (`ak_…`) et le secret.
- « Clés et webhooks » → « Ajouter un endpoint » : indiquez l’URL de votre gestionnaire, par exemple `https://shop.example/webhooks/coinetic` (en sandbox, `http://localhost:3000/…` est accepté). Conservez le secret du webhook.

Les secrets ne s’affichent **qu’une seule fois**. Placez-les dans les variables d’environnement du serveur :

`.env (ne pas commiter !)`

```bash
API_KEY=ak_...
API_SECRET=...
WEBHOOK_SECRET=...
```

## 2. Téléchargez le client

Le client tient en un seul fichier, sans dépendances externes : signature des requêtes, création et lecture des factures, vérification des webhooks. [Télécharger pour votre langage →](https://coinetic.money/fr/docs/sdks/)

## 3. Créez une facture

Le prix est une chaîne, en USD, EUR, USDT ou USDC. Dérivez l’`Idempotency-Key` du numéro de commande : une nouvelle tentative après un timeout renverra la même facture.

**Node.js** — `create-invoice.js`

```js
import { CoineticClient } from "./cryptopay.js";

const cp = new CoineticClient({ baseUrl: "https://sandbox.coinetic.money", keyId: process.env.API_KEY, secret: process.env.API_SECRET });

const invoice = await cp.createInvoice({
  order_id: "ORDER-1001",                 // votre numéro de commande, unique par marchand
  price_amount: "25.00",                  // une chaîne, pas un nombre
  price_currency: "USD",
  return_url: "https://shop.example/orders/ORDER-1001",
  metadata: { user_id: "42" },
}, "order-ORDER-1001");                   // Idempotency-Key

console.log(invoice.checkout_url);        // https://sandbox.coinetic.money/pay/inv_…#t=…
```

**PHP** — `create-invoice.php`

```php
require 'Cryptopay.php';

$cp = new \Cryptopay\Client('https://sandbox.coinetic.money', getenv('API_KEY'), getenv('API_SECRET'));

$invoice = $cp->createInvoice([
    'order_id'       => 'ORDER-1001',
    'price_amount'   => '25.00',
    'price_currency' => 'USD',
    'return_url'     => 'https://shop.example/orders/ORDER-1001',
    'metadata'       => ['user_id' => '42'],
], 'order-ORDER-1001');

echo $invoice['checkout_url'];
```

**Python** — `create_invoice.py`

```py
import os
from cryptopay import CoineticClient

cp = CoineticClient("https://sandbox.coinetic.money", os.environ["API_KEY"], os.environ["API_SECRET"])

invoice = cp.create_invoice({
    "order_id": "ORDER-1001",
    "price_amount": "25.00",
    "price_currency": "USD",
    "return_url": "https://shop.example/orders/ORDER-1001",
    "metadata": {"user_id": "42"},
}, "order-ORDER-1001")

print(invoice["checkout_url"])
```

**Go** — `main.go`

```go
cp := &cryptopayclient.Client{
	BaseURL: "https://sandbox.coinetic.money",
	KeyID:   os.Getenv("API_KEY"),
	Secret:  os.Getenv("API_SECRET"),
	HTTP:    &http.Client{Timeout: 10 * time.Second},
}
inv, err := cp.CreateInvoice(ctx, cryptopayclient.CreateInvoice{
	OrderID:       "ORDER-1001",
	PriceAmount:   "25.00",
	PriceCurrency: "USD",
	ReturnURL:     "https://shop.example/orders/ORDER-1001",
	Metadata:      map[string]string{"user_id": "42"},
}, "order-ORDER-1001")
if err != nil {
	return err
}
fmt.Println(inv.CheckoutURL)
```

## 4. Envoyez le client vers le paiement

Redirigez le navigateur vers `invoice.checkout_url` (HTTP 303). Le client choisit sa devise et voit l’adresse, le montant et le QR code. En sandbox, des boutons de paiement test s’affichent sous les coordonnées de paiement : « Payer le montant exact », « Sous-paiement de 10 % », « Surpaiement de 10 % », « Moitié du montant », « Payer le solde ».

> **Pas d’iframe.** La page de paiement interdit l’intégration en iframe : c’est une protection contre la substitution d’adresse. Ouvrez-la dans le même onglet ou dans le navigateur système de l’application.

## 5. Recevez le webhook

L’ordre est toujours le même : **vérifier la signature → écarter les doublons → revérifier le statut via l’API → livrer la commande une seule fois → répondre 2xx**.

**Node.js** — `webhook.js`

```js
import express from "express";
import { verifyWebhook } from "./cryptopay.js";
// cp : le client de l’étape 3. alreadyProcessed / markProcessed / fulfil : vos propres fonctions.

const app = express();

// express.raw : la signature porte sur les octets bruts, n’activez pas express.json() sur cette route
app.post("/webhooks/coinetic", express.raw({ type: "application/json" }), async (req, res) => {
  let event;
  try {
    event = verifyWebhook(process.env.WEBHOOK_SECRET, req.headers, req.body);
  } catch (e) {
    return res.status(e.status ?? 400).end();               // 401 : signature invalide, 400 : timestamp trop ancien
  }
  try {
    const eventId = req.headers["x-webhook-id"];
    if (await alreadyProcessed(eventId)) return res.sendStatus(200);
    const inv = await cp.getInvoice(event.data.invoice_id); // le statut vient de l’API, pas du webhook
    if (inv.status === "paid" || inv.status === "overpaid") await fulfil(inv.order_id);
    await markProcessed(eventId);
    res.sendStatus(200);
  } catch (e) {
    console.error(e);
    res.sendStatus(500);                                    // hors 2xx, Coinetic relancera la livraison
  }
});

app.listen(3000);
```

**PHP** — `webhook.php`

```php
require 'Cryptopay.php';

$headers = array_change_key_case(getallheaders(), CASE_LOWER);
$raw = file_get_contents('php://input');                   // corps brut, avant json_decode
try {
    $event = \Cryptopay\verify_webhook(getenv('WEBHOOK_SECRET'), $headers, $raw);
} catch (\Cryptopay\CryptopayException $e) {
    http_response_code($e->status);
    exit;
}
if (already_processed($headers['x-webhook-id'])) { http_response_code(200); exit; }

$inv = $cp->getInvoice($event['data']['invoice_id']);       // le statut vient de l’API
if (in_array($inv['status'], \Cryptopay\PAID_STATUSES, true)) {
    fulfil($inv['order_id']);
}
mark_processed($headers['x-webhook-id']);
http_response_code(200);
```

**Python** — `webhook.py`

```py
import os
from flask import Flask, request
from cryptopay import verify_webhook, CryptopayError, PAID_STATUSES

app = Flask(__name__)

@app.post("/webhooks/coinetic")
def webhook():
    headers = {k.lower(): v for k, v in request.headers.items()}
    try:
        event = verify_webhook(os.environ["WEBHOOK_SECRET"], headers, request.get_data())
    except CryptopayError as e:
        return "", e.status
    if already_processed(headers["x-webhook-id"]):
        return "", 200
    inv = cp.get_invoice(event["data"]["invoice_id"])      # le statut vient de l’API
    if inv["status"] in PAID_STATUSES:
        fulfil(inv["order_id"])
    mark_processed(headers["x-webhook-id"])
    return "", 200
```

**Go** — `webhook.go`

```go
func webhook(w http.ResponseWriter, r *http.Request) {
	raw, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 1<<20))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	if err := cryptopayclient.VerifyWebhook(os.Getenv("WEBHOOK_SECRET"), r.Header, raw, time.Now(), 5*time.Minute); err != nil {
		w.WriteHeader(http.StatusUnauthorized)
		return
	}
	var ev struct {
		Data struct{ InvoiceID string `json:"invoice_id"` } `json:"data"`
	}
	if err := json.Unmarshal(raw, &ev); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	inv, err := cp.GetInvoice(r.Context(), ev.Data.InvoiceID) // le statut vient de l’API
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError) // Coinetic relancera
		return
	}
	if cryptopayclient.PaidStatuses[inv.Status] {
		fulfilOnce(inv.OrderID)
	}
	w.WriteHeader(http.StatusOK)
}
```

## 6. Renvoyez le client vers votre site

Après le paiement, la page affiche un bouton « Retour à la boutique » qui mène à votre `return_url`. Affichez-y le statut de la commande **tiré de votre propre base**. Si le webhook n’est pas encore arrivé, revérifiez via `GET /v1/invoices/{id}`.

## Et ensuite ?

- [Testez tous les scénarios en sandbox](https://coinetic.money/fr/docs/sandbox/) : sous-paiement, surpaiement, facture expirée.
- [Traitez les autres événements](https://coinetic.money/fr/docs/webhooks/) : `underpaid`, `expired`, `reorged`.
- [Suivez la checklist de mise en production](https://coinetic.money/fr/docs/go-live/) avant d’encaisser de vrais paiements.
