> ## Documentation Index
> Fetch the complete documentation index at: https://www.zippendo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Egendefinerte kanaler

> Koble din egen nettbutikk eller ditt ERP-system til Zippendo med signerte ordreinnsendinger og REST API-et.

En egendefinert kanal lar din egen nettbutikk, ditt ERP-system eller en annen ordrekilde du styrer, sende ordrer inn i Zippendo når det ikke finnes en ferdig tilkobling for den. Den fungerer i to retninger:

* **Send ordrer inn**: systemet ditt sender signerte webhook-hendelser til kanalens egen **mottaks-URL**, eller kaller [REST API-et](/docs/api-reference/overview) (offisielle SDK-er er tilgjengelige).
* **Få svar tilbake**: abonner på [utgående webhooks](/docs/no/quickstarts/webhooks) fra Zippendo (`shipment.dispatched`, `tracking.updated` og flere) for å motta sporingsnumre og statusendringer.

## 1. Opprett kanalen

Klikk **Ordrekanaler** i [app.zippendo.com](https://app.zippendo.com), åpne fanen **Katalog** og klikk **Opprett kanal** på kortet **Egendefinert kanal**. Eller opprett den via API-et:

```bash theme={null}
curl -X POST https://api.zippendo.com/orgs/{orgId}/order-channels \
  -H "Authorization: Bearer zipp_..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "My webshop", "type": "custom" }'
```

## 2. Generer signeringshemmeligheten

Klikk **Generer hemmelighet** på kanalens innstillingsside, eller kall `POST /orgs/{orgId}/order-channels/{channelId}/webhook-secret`. Svaret inneholder **mottaks-URL-en** og **hemmeligheten**:

```json theme={null}
{
  "secret": "zwhs_...",
  "webhookUrl": "https://api.zippendo.com/webhooks/order-channels/{channelId}",
  "createdAt": "2026-09-02T12:00:00.000Z"
}
```

<Warning>
  Hemmeligheten vises **bare én gang**. Lagre den i konfigurasjonen til systemet ditt. Hvis du erstatter hemmeligheten, opprettes en ny, og den gamle slutter å virke umiddelbart. Hvis du tilbakekaller den, avviser mottaks-URL-en alle innsendinger til det finnes en ny hemmelighet.
</Warning>

## 3. Send ordrer

Send en `POST` til mottaks-URL-en med to headere:

| Header | Verdi |
| - | - |
| `X-Zippendo-Topic` | `order.created`, `order.updated`, `order.cancelled` eller `ping` |
| `X-Zippendo-Signature` | HMAC-SHA256 av **den rå innholdsdelen av forespørselen**, hex-kodet, med signeringshemmeligheten din som nøkkel |

```javascript theme={null}
import crypto from "node:crypto"

const body = JSON.stringify(order)
const signature = crypto.createHmac("sha256", process.env.ZIPPENDO_WEBHOOK_SECRET)
  .update(body)
  .digest("hex")

await fetch(webhookUrl, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Zippendo-Topic": "order.created",
    "X-Zippendo-Signature": signature
  },
  body
})
```

### Ordrenyttelast (`order.created` / `order.updated`)

Begge emnene oppfører seg likt: ordren **upserts** på `externalId`, så gjentatte leveringer og oppdateringer i feil rekkefølge er trygge. Send det systemet ditt synes er enklest.

```json theme={null}
{
  "externalId": "SO-10422",
  "orderNumber": "#1042",
  "customerName": "Anna Jensen",
  "customerEmail": "anna@example.dk",
  "shippingAddress": {
    "name": "Anna Jensen",
    "address1": "Nørregade 12",
    "city": "København",
    "postalCode": "1165",
    "countryCode": "DK",
    "phone": "+45 12 34 56 78"
  },
  "orderLines": [
    { "name": "Wool Sweater", "sku": "SKU-1042-BLK", "quantity": 2, "unitPrice": 499.0, "weight": 0.5, "weightUnit": "kg" }
  ],
  "totalAmount": 998.0,
  "currency": "DKK",
  "shippingMethodTitle": "GLS Hjemmelevering"
}
```

| Felt | Påkrevd | Merknader |
| - | - | - |
| `externalId` | ✔ | Ordre-ID-en i systemet ditt, brukt som idempotensnøkkel |
| `orderNumber` | ✔ | Lesbart ordrenummer |
| `orderLines` | ✔ | Minst én linje (`name`, `quantity`, og eventuelt `sku`, `unitPrice`, `weight`, …) |
| `shippingAddress` | | Trengs for at en sending skal opprettes |
| `shippingMethodTitle` | | Sammenlignes med kanalens koblinger for leveringsmåter for å velge en fraktregel |
| `serviceCode` | | Eksplisitt kode på formen `{carrier}:{product}:{ruleId}[\|{servicePointId}]`, og har forrang over koblingen |
| `customerName`, `customerEmail`, `subtotalAmount`, `totalAmount`, `currency`, `notes` | | Valgfri metadata |

### Nyttelast for kansellering (`order.cancelled`)

```json theme={null}
{ "externalId": "SO-10422" }
```

### Tilkoblingstest (`ping`)

Enhver signert innholdsdel med `X-Zippendo-Topic: ping` returnerer `200 { "received": true }` uten å endre data. Bruk den til å sjekke signeringskoden din.

### Svar

| Status | Betydning |
| - | - |
| `200` | Leveringen er godtatt og behandlet |
| `400` | Manglende eller ukjent topic-header, en nyttelast som ikke besto valideringen, eller en kanal som er slått av (**Kanal aktivert** er av) |
| `401` | Signaturverifiseringen mislyktes (feil hemmelighet, manglende header, eller ingen hemmelighet er opprettet ennå) |
| `404` | Ukjent kanal-ID |
| `429` | [Grensen for mottak](/docs/api-reference/rate-limits) er nådd. Prøv igjen etter ventetiden i `Retry-After` |
| `5xx` | Behandlingen mislyktes. Prøv leveringen på nytt: upsert gjør ny levering trygg |

## Hva som skjer med en innsendt ordre

1. Ordren upserts i kanalen (og arver kanalens [merkevare](/docs/no/settings/brands), hvis den har en).
2. En fraktregel finnes: den eksplisitte `serviceCode`, ellers kanalens **koblinger for leveringsmåter** sammenlignet med `shippingMethodTitle`.
3. En sending opprettes. Sendinger med en samsvarende regel er klare til å sendes. Hvis bare en **Standard avsenderadresse** er satt, opprettes et utkast i stedet.
4. Hvis **Send sendinger automatisk** er på for kanalen, sendes en sending med en samsvarende regel til transportøren med en gang, og fraktetiketten havner i Zippendo (automatisk utskrift på regelen gjelder).

## REST som alternativ

Hvis du foretrekker forespørsel og svar fremfor webhooks, oppretter du ordrer via API-et med et [API-token](/docs/no/settings/api-settings):

```bash theme={null}
curl -X POST https://api.zippendo.com/orgs/{orgId}/orders \
  -H "Authorization: Bearer zipp_..." \
  -H "Content-Type: application/json" \
  -d '{
    "orderChannelId": "{channelId}",
    "orderNumber": "#1042",
    "externalId": "SO-10422",
    "orderLines": [{ "name": "Wool Sweater", "quantity": 2 }],
    "shippingAddress": { "name": "Anna Jensen", "address1": "Nørregade 12", "city": "København", "postalCode": "1165", "countryCode": "DK" },
    "shippingMethodTitle": "GLS Hjemmelevering"
  }'
```

* En duplisert `externalId` på samme kanal returnerer **`409 ORDER_EXISTS`**. Behandle den som «allerede mottatt».
* Hvis du sender `shippingRuleId` eller `shippingMethodTitle` (eller slår på **Send sendinger automatisk** for kanalen), opprettes sendingen i samme kall, akkurat som ved en innsending.
* Ordrekanaler er en del av det offentlige API-et, så [SDK-ene](/docs/no/sdks/overview) dekker hvert trinn: opprett kanalen, generer hemmeligheten, send ordrer og list sendinger.

## Få sporing tilbake

Zippendo varsler systemet ditt via [utgående webhooks](/docs/no/quickstarts/webhooks): abonner på `shipment.dispatched` og `tracking.updated` under **Innstillinger → Webhooks**. Sendinger har ordrenummeret ditt som `reference`, og nyttelasten inneholder `orderId` for oppslag.

## Neste steg

<CardGroup cols={2}>
  <Card title="Utgående webhooks" icon="webhook" href="/docs/no/quickstarts/webhooks">
    Motta sporings- og statushendelser, og verifiser signaturene våre.
  </Card>

  <Card title="API-referanse" icon="terminal" href="/docs/api-reference/overview">
    Alle endepunkter for ordrekanaler og ordrer, med eksempler.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.