Fyndare API

Integrera dina företagssystem med Fyndare. Skapa, hantera och synka annonser programmatiskt.

v1.0 — StabilREST APIOpenAPI-spec (JSON)

Snabbstart

  1. Skapa ett företagskonto på fyndare.se/register (välj "Företag")
  2. Gå till Dashboard → API och begär API-åtkomst
  3. När din ansökan är godkänd skapar du en API-nyckel (nyckeln visas bara en gång — spara den!)
  4. Gör din första förfrågan:
API-nyckel skapad-dialogen i Fyndare-dashboarden: den färska nyckeln visas en enda gång med 'Kopiera'-knapp och amber varning om att spara direkt
Dialogen som visas direkt efter Skapa nyckel: hela nyckeln visas en enda gång — kopiera den innan du stänger rutan, annars måste du regenerera.
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://fyndare.se/api/v1/me
bash

Bas-URL: https://fyndare.se/api/v1

API-nycklar-sidan med en aktiv nyckel i listan, API-dokumentation-länk och kortet Förbyggda lösningar med knapparna Ladda ned plugin, Installationsguide och Öppna integrationsflödet
Dashboard → API efter att första nyckeln skapats. Om du hellre vill slippa bygga mot API:et: kortet Förbyggda lösningar längst ner har knappen Öppna integrationsflödet som hoppar direkt till Fyndare Connector-pluginet.

Autentisering

Alla API-förfrågningar kräver en Bearer-token i Authorization-headern.

Authorization: Bearer fyn_live_abc123...
http

Live-nycklar

fyn_live_*

Skapar riktiga, publikt synliga annonser.

Test-nycklar

fyn_test_*

Skapar utkastannonser. Inte synliga publikt. Säkra för tester.

API-nycklar hashas med SHA-256 och lagras aldrig i klartext. En nyckel visas bara en gång vid skapandet. Om du tappar bort den, återkalla den gamla nyckeln och skapa en ny.

Svarsformat

Alla svar använder ett konsekvent JSON-format:

Lyckat
{
  "success": true,
  "data": { ... },
  "meta": {
    "requestId": "req_a1b2c3d4e5f6",
    "timestamp": "2026-02-15T14:30:00.000Z"
  }
}
json
Paginerat
{
  "success": true,
  "data": [ ... ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "pages": 8,
    "hasMore": true
  },
  "meta": { ... }
}
json
Fel
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Title must be at least 5 characters",
    "details": [
      { "field": "title", "message": "Title must be at least 5 characters" }
    ]
  },
  "meta": { ... }
}
json

Begränsningar

MetodGränsFönster
GET300 förfrågningarper minut
POST / PATCH / PUT / DELETE30 förfrågningarper minut

När gränsen överskrids får du ett 429-svar med felkoden RATE_LIMITED. Vänta och försök igen med exponentiell backoff.

Referensdata

Använd dessa endpoints för att hitta giltiga kategori- och platssluggar när du skapar annonser. Cachea dem lokalt — de ändras sällan.

GET/categories

Lista alla kategorier med underkategorier och deras attribut.

GET/locations

Lista alla 21 svenska län med tillhörande kommuner.

Annonser

GET/listings

Lista dina egna annonser. Stöder paginering, statusfilter och sortering.

Sökparametrar: page, limit (max 100), status, sort (newest|oldest|price_asc|price_desc), externalId
POST/listings

Skapa en ny annons.

Begärankropp
{
  "title": "Volvo V60 2019",
  "description": "Välskött familjebil med...",
  "price": 259000,
  "condition": "GOOD",
  "categorySlug": "fordon-bilar",
  "locationLan": "vastra-gotalands-lan",
  "locationKommun": "goteborg",
  "externalId": "INV-001",
  "phone": "+46701234567",
  "images": [
    { "url": "https://example.com/car1.jpg", "order": 0 },
    { "url": "https://example.com/car2.jpg", "order": 1 }
  ]
}
json
Tips: Använd Idempotency-Key-headern för att undvika dubbletter vid nätverksomförsök.
GET/listings/:id

Hämta en enskild annons via ID.

PATCH/listings/:id

Partiell uppdatering. Skicka bara de fält du vill ändra.

DELETE/listings/:id

Soft-delete av en annons (status sätts till REMOVED).

POST/listings/:id/sold

Markera en annons som såld. Fungerar bara på ACTIVE-annonser.

POST/listings/:id/renew

Förnya en annons (+30 dagar). Fungerar på ACTIVE- eller EXPIRED-annonser.

Bilder

Bilder kan laddas upp på tre sätt: via URL, multipart-uppladdning eller base64-inbäddning. Max 30 bilder per annons.

POST/listings/:id/images

Lägg till en bild på en annons. Stöder URL, multipart eller base64.

DELETE/listings/:id/images/:imageId

Ta bort en bild från en annons.

PATCH/listings/:id/images/reorder

Ändra ordning på bilder genom att skicka en array med bild-ID i önskad ordning.

Externt ID / Upsert

Upsert-mönstret är det rekommenderade sättet att synka ditt lager. Använd ditt eget produkt-ID som externalId — Fyndare skapar eller uppdaterar automatiskt.

PUT/listings/by-external-id/:externalId

Om en annons med detta externalId finns på ditt konto uppdateras den. Annars skapas en ny.

Exempel: Synka lagerpost
curl -X PUT https://fyndare.se/api/v1/listings/by-external-id/INV-001 \
  -H "Authorization: Bearer fyn_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Volvo V60 2019",
    "description": "Updated description...",
    "price": 249000,
    "condition": "GOOD",
    "categorySlug": "fordon-bilar",
    "locationLan": "vastra-gotalands-lan",
    "locationKommun": "goteborg"
  }'
bash

Bulk-operationer

Bearbeta upp till 50 poster per förfrågan. Partiell framgång stöds — varje post bearbetas oberoende.

POST/listings/bulk

Skapa annonser i bulk (max 50).

PATCH/listings/bulk

Uppdatera annonser i bulk via ID eller externalId (max 50).

DELETE/listings/bulk

Ta bort annonser i bulk (max 50).

POST/listings/bulk/sold

Markera annonser som sålda i bulk (max 50).

Svarsformat för bulk
{
  "success": true,
  "data": {
    "total": 3,
    "created": 2,
    "failed": 1,
    "results": [
      { "index": 0, "success": true, "data": { "id": "clxx..." } },
      { "index": 1, "success": true, "data": { "id": "clxy..." } },
      { "index": 2, "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Price is required" } }
    ]
  }
}
json

Webhooks

Ta emot HTTP-notiser när händelser inträffar. Max 5 webhook-endpoints per konto.

Händelser som stöds

HändelseUtlösare
listing.createdAnnons skapad
listing.updatedAnnons uppdaterad
listing.soldMarkerad som såld
listing.expiredAnnons har gått ut
listing.removedAdmin tog bort annonsen
message.receivedNytt meddelande på din annons
listing.favoritedNågon favoritmarkerade din annons
POST/webhooks

Skapa en webhook-endpoint. Secret returneras bara en gång.

GET/webhooks

Lista dina webhook-endpoints.

PATCH/webhooks/:id

Uppdatera URL, händelser eller aktiv status.

DELETE/webhooks/:id

Ta bort en webhook-endpoint.

POST/webhooks/:id/test

Skicka en test-leverans av webhook.

GET/webhooks/:id/deliveries

Visa leveranshistorik.

Webhook-payload

{
  "event": "listing.sold",
  "deliveryId": "del_abc123",
  "timestamp": "2026-02-15T14:30:00.000Z",
  "data": {
    "id": "clxx123",
    "externalId": "INV-001",
    "soldAt": "2026-02-15T14:30:00.000Z"
  }
}
json

Headers som följer med varje leverans:

X-Fyndare-Event: listing.sold
X-Fyndare-Delivery: del_abc123
X-Fyndare-Signature: sha256=abc123...
X-Fyndare-Timestamp: 1708012345
http

Verifiera signaturer

Verifiera X-Fyndare-Signature-headern med HMAC-SHA256 och din webhook-secret:

JavaScript
const crypto = require("crypto");

function verifyWebhook(secret, timestamp, body, signature) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(timestamp + "." + body)
    .digest("hex");
  return signature === "sha256=" + expected;
}

// In your handler:
const sig = req.headers["x-fyndare-signature"];
const ts = req.headers["x-fyndare-timestamp"];
const isValid = verifyWebhook(WEBHOOK_SECRET, ts, JSON.stringify(req.body), sig);
javascript
Python
import hmac, hashlib

def verify_webhook(secret, timestamp, body, signature):
    message = f"{timestamp}.{body}"
    expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return signature == f"sha256={expected}"
python

Omförsökspolicy

  • 1:a försöket: omedelbart
  • Omförsök 1: efter 5 minuter
  • Omförsök 2: efter 30 minuter
  • Omförsök 3: efter 2 timmar
  • Efter 10 misslyckade försök i rad: endpoint inaktiveras automatiskt

Återaktivera en inaktiverad endpoint genom att uppdatera den med isActive: true.

Felreferens

KodHTTPBeskrivning
UNAUTHORIZED401Saknad eller ogiltig API-nyckel
FORBIDDEN403Giltig nyckel men otillräckliga rättigheter
NOT_FOUND404Resursen hittades inte
VALIDATION_ERROR400Ogiltig indata (se details-arrayen)
RATE_LIMITED429Gräns överskriden — vänta och försök igen
SERVER_ERROR500Internt fel — försök igen eller kontakta supporten

Kodexempel

cURL — Skapa en annons

curl -X POST https://fyndare.se/api/v1/listings \
  -H "Authorization: Bearer fyn_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-key-123" \
  -d '{
    "title": "Volvo V60 2019",
    "description": "Välskött familjebil med full servicehistorik...",
    "price": 259000,
    "condition": "GOOD",
    "categorySlug": "fordon-bilar",
    "locationLan": "vastra-gotalands-lan",
    "locationKommun": "goteborg"
  }'
bash

JavaScript / Node.js

const API_KEY = "fyn_live_...";
const BASE = "https://fyndare.se/api/v1";

async function createListing(data) {
  const res = await fetch(`${BASE}/listings`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(data),
  });
  return res.json();
}

// Create
const { data: listing } = await createListing({
  title: "Volvo V60 2019",
  description: "Välskött familjebil...",
  price: 259000,
  condition: "GOOD",
  categorySlug: "fordon-bilar",
  locationLan: "vastra-gotalands-lan",
  locationKommun: "goteborg",
});
console.log("Created:", listing.id);

// List
const res = await fetch(`${BASE}/listings?page=1&limit=10`, {
  headers: { "Authorization": `Bearer ${API_KEY}` },
});
const { data: listings } = await res.json();

// Mark as sold
await fetch(`${BASE}/listings/${listing.id}/sold`, {
  method: "POST",
  headers: { "Authorization": `Bearer ${API_KEY}` },
});
javascript

Python

import requests

API_KEY = "fyn_live_..."
BASE = "https://fyndare.se/api/v1"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

# Create listing
resp = requests.post(f"{BASE}/listings", headers=HEADERS, json={
    "title": "Volvo V60 2019",
    "description": "Välskött familjebil...",
    "price": 259000,
    "condition": "GOOD",
    "categorySlug": "fordon-bilar",
    "locationLan": "vastra-gotalands-lan",
    "locationKommun": "goteborg",
})
listing = resp.json()["data"]
print(f"Created: {listing['id']}")

# List
resp = requests.get(f"{BASE}/listings", headers=HEADERS)
listings = resp.json()["data"]

# Mark as sold
requests.post(f"{BASE}/listings/{listing['id']}/sold", headers=HEADERS)
python

Mönster för lager-synk

// Sync your full inventory using the upsert pattern
for (const item of inventory) {
  await fetch(
    `${BASE}/listings/by-external-id/${item.sku}`,
    {
      method: "PUT",
      headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        title: item.name,
        description: item.description,
        price: item.price,
        condition: "NEW",
        categorySlug: item.category,
        locationLan: "vastra-gotalands-lan",
        locationKommun: "goteborg",
      }),
    }
  );
}

// Mark sold items
const soldIds = inventory
  .filter(i => i.sold)
  .map(i => i.fyndareId);

if (soldIds.length > 0) {
  await fetch(`${BASE}/listings/bulk/sold`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ ids: soldIds }),
  });
}
javascript

Konto

GET/me

Hämta dina kontouppgifter och detaljer om API-nyckeln.

GET/me/usage

Hämta användningsstatistik för den aktuella nyckeln.

Sökparametrar: days (1-90, standard 30)

Förbyggda lösningar

Vill du slippa bygga integrationen från grunden? Vi har färdiga paket som kopplar vanliga plattformar till Fyndare med minimal konfiguration.

Fyndare Connector — WordPress / WooCommerce

Ett gratis WordPress-plugin som upptäcker om du har WooCommerce-produkter eller ett fordons-CPT och skickar dina annonser till Fyndare automatiskt. API-nyckel och webhook-nyckel skapas åt dig vid aktivering — ingen manuell konfiguration krävs.

  • Funkar både med och utan WooCommerce (WP-fordons-CPT stöds)
  • Realtidssynk via webhooks — ändringar i butiken speglas på Fyndare inom sekunder
  • Publiceras open source under GPL-2.0
  • Schemalagd polling var 15:e minut som säkerhetsnät