---
title: Snelstart
description: Uw eerste testbetaling met Coinetic in 15 minuten: sandboxsleutel, factuur aanmaken via de API, redirect naar de betaalpagina en webhook ontvangen.
url: https://coinetic.money/nl/docs/quickstart/
lang: nl
---

# Snelstart

Uw eerste betaling in de sandbox binnen 15 minuten. U hebt een server met Node.js, PHP, Python of Go nodig — er zijn voorbeelden voor alle vier.

> **Het eindresultaat.** Uw website maakt een factuur aan, de klant betaalt op de pagina van Coinetic (in de sandbox met een knop), uw server ontvangt een webhook en levert de bestelling precies één keer.

## 1. Haal uw sandboxsleutels op

- Registreer u in het [sandbox-dashboard](https://sandbox.coinetic.money/merchant) en schakel 2FA in.
- ‘Sleutels en webhooks’ → ‘Sleutel aanmaken’: bewaar de `key_id` (`ak_…`) en het secret.
- ‘Sleutels en webhooks’ → ‘Endpoint toevoegen’: de URL van uw handler, bijvoorbeeld `https://shop.example/webhooks/coinetic` (in de sandbox mag ook `http://localhost:3000/…`). Bewaar het webhook-secret.

Secrets worden **één keer** getoond. Zet ze in de omgevingsvariabelen van uw server:

`.env (niet committen!)`

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

## 2. Download de client

De client is één bestand zonder externe dependencies: requests ondertekenen, facturen aanmaken en opvragen, webhooks verifiëren. [Download voor uw taal →](https://coinetic.money/nl/docs/sdks/)

## 3. Maak een factuur aan

De prijs als string, in USD, EUR, USDT of USDC. Baseer de `Idempotency-Key` op het ordernummer: een retry na een time-out geeft dan dezelfde factuur terug.

**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",                 // uw ordernummer, uniek per merchant
  price_amount: "25.00",                  // string, geen getal
  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. Stuur de klant naar de betaalpagina

Redirect de browser naar `invoice.checkout_url` (HTTP 303). De klant kiest een valuta en ziet het adres, het bedrag en een QR-code. In de sandbox staan onder de betaalgegevens knoppen voor testbetalingen: ‘Exact betalen’, ‘Onderbetaling 10%’, ‘Overbetaling 10%’, ‘Half bedrag’, ‘Restant bijbetalen’.

> **Niet in een iframe insluiten.** De betaalpagina staat insluiten niet toe — dat beschermt tegen het vervangen van het adres. Open haar in hetzelfde tabblad of in de systeembrowser van uw app.

## 5. Ontvang de webhook

De volgorde is altijd dezelfde: **handtekening controleren → herhaling negeren → status opnieuw controleren via de API → bestelling één keer leveren → antwoorden met 2xx**.

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

```js
import express from "express";
import { verifyWebhook } from "./cryptopay.js";
// cp — de client uit stap 3. alreadyProcessed / markProcessed / fulfil — uw eigen functies.

const app = express();

// express.raw: de handtekening wordt over de ruwe bytes berekend — gebruik op deze route geen express.json()
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 — onbekende handtekening, 400 — verouderde timestamp
  }
  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); // status uit de API, niet uit de 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);                                    // geen 2xx — Coinetic probeert opnieuw
  }
});

app.listen(3000);
```

**PHP** — `webhook.php`

```php
require 'Cryptopay.php';

$headers = array_change_key_case(getallheaders(), CASE_LOWER);
$raw = file_get_contents('php://input');                   // ruwe body, vóór 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']);       // status uit de 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"])      # status uit de 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) // status uit de API
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError) // Coinetic probeert opnieuw
		return
	}
	if cryptopayclient.PaidStatuses[inv.Status] {
		fulfilOnce(inv.OrderID)
	}
	w.WriteHeader(http.StatusOK)
}
```

## 6. Stuur de klant terug

Na de betaling verschijnt op de pagina de knop ‘Terug naar de winkel’, die naar uw `return_url` leidt. Toon daar de status van de bestelling **uit uw eigen database**. Is de webhook nog niet binnen, controleer dan `GET /v1/invoices/{id}`.

## Volgende stappen

- [Test alle scenario's in de sandbox](https://coinetic.money/nl/docs/sandbox/) — onderbetaling, overbetaling, verlopen factuur.
- [Verwerk de overige events](https://coinetic.money/nl/docs/webhooks/) — `underpaid`, `expired`, `reorged`.
- [Doorloop de go-live-checklist](https://coinetic.money/nl/docs/go-live/) voordat u echt geld accepteert.
