Gå til innholdet
Digilist Dokumentasjon
Book demo

INTEGRASJONER · VIPPS

Vipps Mobilepay

Salesunit-oppsett, callback-URLer, betalings-flyt, refusjons-håndtering, e-faktura. Slik kobler tenants Vipps til sin checkout.

Vipps er den dominerende mobil-betalingen i Norge med >85 % markedsandel blant Digilists innbyggere. Vi integrerer via Vipps eCom v2 og bruker capture-on-confirm-mønster — innbygger autoriserer ved booking, vi capturer først når saksbehandler har godkjent (eller umiddelbart for selvbetjente bookinger).

1. Salesunit-oppsett

Hver tenant har én Vipps “salesunit” registrert hos Vipps. Konfig ligger i tenants.paymentConfig.vipps:

{
msn: "123456", // Merchant Serial Number
subscriptionKey: "encrypted-via-secrets-component",
clientId: "...",
clientSecret: "encrypted-via-secrets-component",
callbackPrefix: "https://api.digilist.no/webhooks/vipps",
fallbackUrl: "https://{tenant}.digilist.no/booking/{bookingId}/return",
isApplePay: false,
authMode: "MERCHANT_HOSTED", // vs. VIPPS_HOSTED
}

2. Betalings-flyt

INNBYGGER DIGILIST VIPPS-API
│ │ │
│ ── velger slot ──> │ │
│ ── klikker betal ─>│ ── POST /payments ─>│
│ │ <── { url, ref } ─ │
│ <── 302 til Vipps ─│ │
│ ── auth i Vipps-app ──────────────────> │
│ <── 302 til fallbackUrl?ref=... ─────── │
│ │ <── webhook /v2/payments/{ref}/status
│ │ Verifiser sig, upd booking
│ <── viser bekreft ─│ │

State-overgangsmatrise

INITIATE → RESERVE → CAPTURE → (REFUND)
CANCEL
EXPIRE (etter 24t hvis ikke auth)
Booking-stateVipps-action
pending_approval (saksbehandler skal godkjenne)INITIATE + RESERVE (innbygger har autorisert, vi capturer ikke ennå)
approvedCAPTURE (saksbehandler godkjent → trekker beløpet)
rejected eller cancelled_before_captureCANCEL (release reservasjon, ingen trekk)
cancelled_after_captureREFUND (helt eller delvis)

3. Callback / webhook

Vipps sender callbacks til https://api.digilist.no/webhooks/vipps/{ref}. Vi verifiserer HMAC, dedupliserer på ref (transactionId), og emit’er webhook.vipps.received på outbox-bussen.

convex/http.ts
http.route({
path: "/webhooks/vipps/:ref",
method: "POST",
handler: httpAction(async (ctx, request) => {
const body = await request.text();
const hmac = request.headers.get("authorization");
if (!verifyVippsHmac(body, hmac)) {
return new Response("invalid signature", { status: 401 });
}
const ref = request.params.ref;
await ctx.runMutation(internal.payments.handleVippsCallback, {
ref,
body: JSON.parse(body),
});
return new Response(null, { status: 200 });
}),
});

4. Refusjon

Refusjon kan utløses av:

  • Saksbehandler kansellerer en godkjent booking via /admin/bookings/{id}/cancel
  • Innbygger kansellerer (hvis lokalets kanselleringspolitikk tillater)
  • System ved force-majeure (stengt lokale)
await payments.refund({
paymentId: payment._id,
amountCents: payment.amountCents, // hel eller delvis
reason: "Lokale stengt grunnet vannlekkasje",
});
// → POST /v2/payments/{ref}/refund
// → emit "payment.refunded"
// → notifications.sendRefundConfirmation

5. E-faktura via Vipps

For tenants som tilbyr “betal senere” støtter Vipps e-faktura (OPTIONS: ["VIPPS_INVOICE"] i initiatePayment). Beløpet sendes til innbyggers nettbank uten kort-trekk.

EgenskapVerdi
Forfall14 dager (konfigurerbart)
BegrensningMin 100 kr, maks 30 000 kr
KID-genereringMod-10 fra bookingId
PåminnelseAuto fra Vipps + duplikat fra Digilist notifications

6. Sandbox vs produksjon

MiljøBase URLBrukes
Testhttps://apitest.vipps.no/All utvikling og staging. Test-MSN 654321.
PRODhttps://api.vipps.no/Etter merchant-aktivering hos Vipps.

7. Operasjon

  • Token-fornyelse: Access-tokens varer 1 time. Vi cacher i secrets-komponenten og fornyer 5 min før utløp.
  • Overvåking: /platform/integrations/vipps viser dispatch-rate, callback-feilrate, latency p50/p95/p99.
  • Avbruddshåndtering: Hvis Vipps er nede > 5 min → fallback til Stripe-kort, banner på checkout.

Beslektet