Developers

Asstio API + MCP

Read-only åtkomst till er Asstio-data — för era egna appar, dashboards, automatiseringar och AI-assistenter. REST för servrar och script, MCP för Claude, Cursor och custom agents. Samma data. Samma auth. v1 är stabil.

Asstio API + MCP

REST eller MCP — välj per use case

Samma underliggande data, samma versioneringskontrakt, samma authmodell. Skillnaden är vem som anropar.

REST

För servrar, script och webbappar

GET och POST mot versionerade endpoints under /api/v1/*. Bygg dashboards, exportera till Power BI, mata Slack-bottar eller köra nattliga jobb mot er Asstio-data.

# Hämta öppna säljordrar
curl https://purchase.svc.order.asstio.com/api/v1/sales-orders \
  -H "Authorization: Bearer $TOKEN"
Versionerad (v1 är stabil) Cursor-paginering ISO 8601 + UTF-8 Inga rate-limits idag
MCP

För Claude, Cursor och AI-agenter

Samma data exponerad som read-only verktyg en AI-assistent kan anropa. Implementerar Model Context Protocol över streamable-HTTP. Claude Desktop, Cline och Cursor sköter OAuth själva.

// claude_desktop_config.json
{
  "mcpServers": {
    "asstio": {
      "url": "https://purchase.svc.order.asstio.com/mcp"
    }
  }
}
10 read-only tools OAuth via discovery (RFC 9728) 60 tool-calls/min/användare Streamable-HTTP

Från noll till första API-anropet — på 5 minuter

1. Skapa ett app-lösenord

Gå till Inställningar → Användare → App-lösenord i Asstio. Skapa ett nytt, ge det ett namn (t.ex. "Power BI"), kopiera lösenordet. App-lösenord är scoped, återkallbara och tänkta för maskin-till-maskin.

2. Växla in mot en JWT

Skicka app-lösenordet till Zitadels token-endpoint för att få en kortlivad Bearer-token. Cacha tills strax innan den löper ut.

3. Ring en endpoint

Lägg Authorization: Bearer <token> på en GET mot /api/v1/customers?q=Acme. Tenanten härleds från tokens iid (InstanceId)-claim — ni passar aldrig tenant-id i URL eller header.

Allt ni behöver för första anropet

GET /api/v1/customers?q=Acme
# Sök efter en kund
curl -G "$ASSTIO/api/v1/customers" \
  --data-urlencode "q=Acme" \
  -H "Authorization: Bearer $TOKEN"
// Response
{
  "items": [{
    "id": 412,
    "contactNumber": 10042,
    "name": "Acme Ltd",
    "orgno": "556677-8899",
    "openOrderCount": 3
  }],
  "nextCursor": null,
  "pageSizeApplied": 50,
  "truncated": false
}
POST /api/v1/sales-invoice-lines
# Vad sålde vi till Acme i april?
curl -X POST "$ASSTIO/api/v1/sales-invoice-lines" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "from": "2026-04-01", "to": "2026-04-30",
      "customerId": 412, "pageSize": 100 }'
// Response (1 av 23 rader)
{
  "productNumber": "WID-12",
  "quantity": 4.0,
  "sumExVat": 12000.00,
  "currencyIsoCode": "SEK"
}
MCP tools/call
// Be Claude i en chatt:
"Visa öppna leverans-rader till Kraft Group"

// Claude anropar:
{
  "method": "tools/call",
  "params": {
    "name": "list_open_order_lines",
    "arguments": { "customerId": 412 }
  }
}
// Claude svarar i naturligt språk
"Kraft Group har 6 order­rader öppna,
 totalt 18 enheter kvar att leverera —
 främst Widget WID-12 och Skruv M8."

Allt är en rad i Orders — diskriminerad av SystemName

Sälj­ordrar, sälj­fakturor, kreditfakturor och inköpsordrar är alla rader i samma tabell. Tre boolska flaggor på OrderStatus avgör vad som räknas som vad i rapporter.

Diskriminator: OrderStatusType.SystemName

SystemNameDokument
SALESORDERSäljorder (bokad, ej skickad)
SALESINVOICESäljfaktura (skickad/fakturerad)
SALESCREDITKreditfaktura (retur/återbetalning)
PURCHASEORDERInköpsorder mot leverantör

Flaggor: IsOrderIntake, IsSales, IsPurchase

  • IsOrderIntake = 1 — Räknas som orderintag. Inkluderar både SALESORDER (väntar leverans) och SALESINVOICE (redan skickad). Definierar orderboken.
  • IsSales = 1 — Räknas som omsättning. Exkluderar preview-/draft-/void-statusar.
  • IsPurchase = 1 — Aktiv inköpsorder (öppen eller pågående), inte stängd/avbruten.

Huvud-endpoints (/sales-orders, /sales-invoices, /purchase-orders) defaultar till den naturliga flaggan för sitt dokumenttyp, så out-of-the-box-siffror matchar Asstios BI. Override via statusKind-parametern eller pinna till en specifik statusId.

13 endpoints. Samma data.

10 read-only endpoints (alla även MCP-verktyg) + 3 endpoints för 3-vägs-matchning av leverantörsfakturor. Klicka på en endpoint för att se request- och response-exempel.

Base URL: https://purchase.svc.order.asstio.com/api/v1/

GET /api/v1/sales-orders
list_sales_orders
Säljorderhuvuden — orderboken. Defaultar till statusKind=intake (statusar med IsOrderIntake=1). Filter på kund, status, datum, valuta, total.

Request

curl -G "$ASSTIO/api/v1/sales-orders" \
  --data-urlencode "customerId=412" \
  --data-urlencode "orderDateFrom=2026-05-01" \
  -H "Authorization: Bearer $TOKEN"

Response item — SalesOrderDto

// 200 OK · X-Asstio-Api-Version: v1
{
  "id": 18743,
  "name": "Webshop order 2026-05",
  "customerId": 412,
  "customerName": "Acme Ltd",
  "customerOrgno": "556677-8899",
  "statusId": 31,
  "statusName": "Bekräftad",
  "dateOrder": "2026-05-12T00:00:00Z",
  "dateDelivery": "2026-05-25T00:00:00Z",
  "dateInvoice": null,
  "dateDue": null,
  "totalExVat": 18250.00,
  "totalVat": 4562.50,
  "totalIncVat": 22812.50,
  "openAmount": 22812.50,
  "isLate": false,
  "isFullyPaid": false,
  "hasShipmentDiscrepancy": false,
  "currencyIsoCode": "SEK"
}
GET /api/v1/purchase-orders
list_purchase_orders
Inköpsordrar mot leverantörer. Defaultar till aktiva PO (IsPurchase=1). Filter på vendor, datum, valuta, mottaget värde och kvar-att-fakturera.

Request

curl -G "$ASSTIO/api/v1/purchase-orders" \
  --data-urlencode "vendorId=78" \
  -H "Authorization: Bearer $TOKEN"

Response item — PurchaseOrderDto

{
  "id": 92044,
  "purchaseNumber": 2026131,
  "vendorId": 78,
  "vendorName": "Northwind Components AB",
  "vendorOrgno": "112233-4455",
  "statusId": 64,
  "statusName": "Beställd",
  "dateOrder": "2026-05-02T00:00:00Z",
  "dateDelivery": "2026-05-30T00:00:00Z",
  "orderTotalExVat": 42500.00,
  "orderTotalIncVat": 53125.00,
  "receivedQtyPercent": null,
  "receivedValueExVat": 12700.00,
  "invoicedValueExVat": 0.00,
  "openToInvoiceExVat": 12700.00,
  "currencyIsoCode": "SEK"
}
GET /api/v1/sales-invoices
list_sales_invoices
Säljfakturahuvuden. Defaultar till intäkts­rader (IsSales=1). Sätt documentType=credit för kreditfakturor, both för kombinerat.

Request

curl -G "$ASSTIO/api/v1/sales-invoices" \
  --data-urlencode "customerId=412" \
  --data-urlencode "dueDateTo=2026-05-20" \
  -H "Authorization: Bearer $TOKEN"

Response item — SalesInvoiceDto

{
  "id": 88312,
  "invoiceNumber": 2026301,
  "customerId": 412,
  "customerName": "Acme Ltd",
  "customerOrgno": "556677-8899",
  "statusName": "Skickad",
  "dateInvoice": "2026-05-01T00:00:00Z",
  "dateDue": "2026-05-31T00:00:00Z",
  "dateOrder": "2026-04-28T00:00:00Z",
  "totalExVat": 12000.00,
  "totalVat": 3000.00,
  "totalIncVat": 15000.00,
  "openAmount": 15000.00,
  "paidAmount": 0.00,
  "isLate": false,
  "isFullyPaid": false,
  "currencyIsoCode": "SEK",
  "documentType": "invoice"
}
POST /api/v1/sales-invoice-lines
list_sales_invoice_lines
Sålda artikelrader — svar på "vad har vi sålt". POST eftersom filterytan är bred. Defaultar till lines från IsSales=1-fakturor.

Request body

{
  "from": "2026-01-01T00:00:00Z",
  "to": "2026-05-20T00:00:00Z",
  "customerId": 412,
  "productId": null,
  "statusId": null,
  "includeNonSales": false,
  "pageSize": 100
}

Response item — SalesInvoiceLineDto

{
  "invoiceId": 88312,
  "invoiceNumber": 2026301,
  "lineId": 410551,
  "productNumber": "WID-12",
  "description": "Widget, large",
  "quantity": 4.0,
  "qtyDelivered": 4.0,
  "price": 3000.00,
  "sumExVat": 12000.00,
  "sumIncVat": 15000.00,
  "currencyIsoCode": "SEK"
}
GET /api/v1/open-order-lines
list_open_order_lines
Säljorderrader med qtyLeftToDeliver > 0. Filter per kund, produkt eller lager. Sätt includeFullyDelivered=true för att även se färdigleveranser.

Request

curl -G "$ASSTIO/api/v1/open-order-lines" \
  --data-urlencode "customerId=412" \
  -H "Authorization: Bearer $TOKEN"

Response item — OpenOrderLineDto

{
  "orderId": 18743,
  "orderName": "Webshop order 2026-05",
  "lineId": 411099,
  "productNumber": "WID-12",
  "description": "Widget, large",
  "qtyOrdered": 10.0,
  "qtyDelivered": 4.0,
  "qtyLeftToDeliver": 6.0,
  "dateDelivery": "2026-05-25T00:00:00Z",
  "customerName": "Acme Ltd",
  "statusName": "Bekräftad"
}
GET /api/v1/warehouse-stock
get_warehouse_stock
Saldo per produkt per lagerplats. qtyDistributable färdig­räknad på servern. pageSize max 200.

Request

curl -G "$ASSTIO/api/v1/warehouse-stock" \
  --data-urlencode "productId=9921" \
  -H "Authorization: Bearer $TOKEN"

Response item — WarehouseStockRowDto

{
  "productId": 9921,
  "productNumber": "WID-12",
  "warehouseName": "Main",
  "locationName": "A-12-3",
  "qtyInStock": 47.0,
  "qtyIncoming": 20.0,
  "qtyOutgoing": 6.0,
  "qtyDistributable": 61.0
  // qtyInStock - qtyOutgoing + qtyIncoming
}
GET /api/v1/vendor-prices
get_vendor_prices_for_product
Leverantörspriser för en specifik produkt. productId är obligatorisk. Filter på supplierId och currencyCode.

Request

curl -G "$ASSTIO/api/v1/vendor-prices" \
  --data-urlencode "productId=9921" \
  -H "Authorization: Bearer $TOKEN"

Response item — VendorPriceDto

{
  "productId": 9921,
  "productNumber": "WID-12",
  "supplierId": 78,
  "supplierName": "Northwind Components AB",
  "supplierProductNumber": "NW-W-LRG",
  "price": 850.00,
  "currencyIsoCode": "SEK",
  "leadTimeDays": null,
  "validFrom": null,
  "validTo": null
}
GET /api/v1/products/find
find_product
Slå upp produkt på namn, artikelnummer eller beskrivning. q obligatorisk. Returnerar upp till limit kandidater (1–20, default 10) — array, inte PageResponse.

Request

curl -G "$ASSTIO/api/v1/products/find" \
  --data-urlencode "q=WID" \
  --data-urlencode "limit=10" \
  -H "Authorization: Bearer $TOKEN"

Response — array av ProductFindDto

[
  {
    "productId": 9921,
    "productNumber": "WID-12",
    "description": "Widget, large",
    "barcode": null,
    "isActive": true
  }
]
GET /api/v1/customers
list_customers
Sök eller lista kunder. Fritext mot id, namn eller orgnr. Sätt inactive=true för att inkludera inaktiva.

Request

curl -G "$ASSTIO/api/v1/customers" \
  --data-urlencode "q=Acme" \
  -H "Authorization: Bearer $TOKEN"

Response item — CustomerDto

{
  "id": 412,
  "contactNumber": 10042,
  "name": "Acme Ltd",
  "orgno": "556677-8899",
  "currencyIsoCode": null,
  "inactive": false,
  "openOrderCount": 3
}
GET /api/v1/customers/{customerId}
get_customer
Full kunddetalj: kreditlimit, förfallna ordrar, kreditstopp, betalnings-/leveransvillkor, prislista, vat-typ. 404 om kunden inte finns eller är i annan tenant.

Request

curl "$ASSTIO/api/v1/customers/412" \
  -H "Authorization: Bearer $TOKEN"

Response — CustomerDetailDto

{
  "id": 412,
  "contactNumber": 10042,
  "name": "Acme Ltd",
  "orgno": "556677-8899",
  "creditLimit": 250000.00,
  "overdueOrderSum": 4200.00,
  "creditStop": false,
  "paymentTermName": "30 dagar netto",
  "deliveryTermName": "Fritt vårt lager",
  "priceListName": "Standard",
  "orderCount": 84,
  "inactive": false
}
GET /api/v1/purchase-invoice-matches/{invoiceId}
3-vägs-matchning
Top-5 kandidat-inleveransrader per fakturarad — med score, signaler (VendorSku, PriceExact, …), variances och isAutoEligible-flagga. Read-only, memory-cachad 30 sek per draft.

Request

curl "$ASSTIO/api/v1/purchase-invoice-matches/5012" \
  -H "Authorization: Bearer $TOKEN"

Response — PurchaseInvoiceMatchResponseDto

{
  "invoiceId": 5012,
  "tolerances": {
    "qtyPercent": 0.02,
    "pricePercent": 0.01,
    "dateWindowDays": 14,
    "autoEligibleScore": 70
  },
  "suggestions": [{
    "invoiceLineIndex": 0,
    "productNumber": "PROD-A",
    "quantity": 100,
    "candidates": [{
      "orderId": 9001,
      "orderItemId": 88012,
      "score": 100,
      "reasons": ["VendorSku", "QtyExact", "PriceExact"],
      "isAutoEligible": true
    }]
  }]
}
POST /api/v1/purchase-invoice-matches/{invoiceId}/confirm
confirm
Spara användarbekräftade (fakturarad → inleverans)-par på draften. Flera receipts kan knytas till samma invoiceLineIndex. Bokar inte verifikationen — det är fortfarande ett separat manuellt steg.

Request body

{
  "matches": [
    {
      "invoiceLineIndex": 0,
      "orderItemId": 88012,
      "invTransactionId": 130045
    }
  ]
}

Response

{
  "invoiceId": 5012
}
POST /api/v1/purchase-invoice-matches/{invoiceId}/match-whole-order
match_whole_order
One-click-shortcut: knyt alla obokade inleveranser på vald PO till draften, fördelade per fakturarad av scorern (best-fit). Bra när AI-radextraktionen missade rader och fakturan mappar mot en PO.

Request body

{
  "orderId": 9001
}

Response

{
  "invoiceId": 5012
}

Use cases redan i drift hos våra kunder

Realtids­dashboards i Power BI

Hämta säljorder, fakturarader och lagerstatus direkt — ingen export, ingen ETL, alltid färsk data.

Claude som affärsanalytiker

"Visa mig de tre största kunderna med förfallna fakturor över 10 000 kr" — Claude anropar list_customers + list_sales_invoices och svarar direkt.

Slack-notifieringar

Pollera open-order-lines nattligt och posta i Slack om något ligger över 30 dagar utan delleverans.

Prisjämförelse mellan leverantörer

Kör vendor-prices för varje aktiv artikel — flagga när bästa pris ligger hos en leverantör ni inte använt på 6 månader.

AI-driven kundbrev

Be Cursor / Claude generera personliga uppföljnings­mejl baserat på kundens specifika orderhistorik från sales-invoice-lines.

Custom integrationer

Bygg er egen koppling mellan Asstio och whatever — CRM, BI, e-postmarketing, supportverktyg. Inga konsulttimmar krävs.

En auth-modell. Funkar för båda.

Varje request bär en Zitadel JWT i Authorization: Bearer-headern. Tenanten härleds från tokens iid (InstanceId)-claim.

Webb-användare

Användare i Asstios egna webbgränssnitt har redan en token i sessionen. Er in-browser-kod kan läsa den och göra API-anrop direkt.

Backend / cron-jobb

Skapa ett app-lösenord i Asstio (under användarinställningar). Växla mot Zitadel för en token. Cacha tills den löper ut. App-lösenord är scoped och återkallbara — bädda aldrig in vanliga användarlösenord.

AI-assistenter via MCP

Claude Desktop, Cline och liknande sköter OAuth själva via vår RFC 9728 OAuth Protected Resource discovery-endpoint. Paste-baserad fallback för enklare klienter.

v1 · STABILT

Versions­kontrakt

Inuti v1 gör vi bara additiva ändringar — nya endpoints, nya valbara fält, nya query-parametrar. Existerande fältnamn, typer och default-beteenden ändras inte. Breaking changes landar i v2 på en separat URL-prefix. v1 fortsätter köra tills sista integratorn flyttat över.

Varje response under /api/v1/* bär headern X-Asstio-Api-Version: v1 — pin emot den om ni vill ha försvar mot oavsiktliga uppgraderingar.

ERRORS

ErrorEnvelope på allt utom 2xx

Non-2xx responses returnerar samma struktur — code, message och valfritt traceId. 401 = saknar/utgången token, 403 = rätt token men fel scope, 404 = resource inte i tenant, 429 = MCP rate-limit (se Retry-After), 500 = serverfel (citera traceId till support).

{
  "code": "not_found",
  "message": "Customer 99999 not found",
  "traceId": null
}
Få access

Redo att börja bygga?

Kontakta oss för ett app-lösenord och URL till er tenant — och säg gärna vad ni vill bygga, så pekar vi mot rätt endpoints.

Kontakta oss Boka demo →