fiken — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited fiken (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Norwegian accounting API integration for Fiken (fiken.no). Covers invoices, credit notes, offers, contacts, products, payments, and account balances.
When this skill is activated, detect the Fiken configuration in this order:
~/.config/fiken-api/credentials.json existsFIKEN_API_TOKEN is set in the environment (via .env)#### Centralized (~/.config/fiken-api/)
If ~/.config/fiken-api/credentials.json exists:
import { getFikenClient, listAccounts } from '~/.config/fiken-api/client.mjs'
// Default account
const fiken = getFikenClient()
const contacts = await fiken.getContacts()
// Specific account
const other = getFikenClient('account-name')
// List available accounts
const accounts = listAccounts()The centralized client handles multi-account switching, auto-includes bank account numbers, and provides account-specific config (vatType, incomeAccount, etc.) via fiken.config.
#### Project-local (.env)
If FIKEN_API_TOKEN is in the environment:
require('dotenv').config();
const fiken = require('./skills/fiken/scripts/client');The project-local client reads from environment variables:
FIKEN_API_TOKEN=... # From Fiken > Innstillinger > API
FIKEN_COMPANY_SLUG=... # Your company slug (from dashboard URL)If no configuration is detected, guide the user through setup:
Step 1: Get an API token
{numeric-id}.{alphanumeric-key}Step 2: Find your company slug
https://fiken.no/foretak/{slug}/...GET https://api.fiken.no/api/v2/companies with the token to list all accessible companiesStep 3: Choose setup method
Use AskUserQuestion to ask the user:
If project-local (.env):
.env with FIKEN_API_TOKEN and FIKEN_COMPANY_SLUGscripts/client.js (bundled with this skill)fiken.getContacts() or fiken.isFikenConfigured()If centralized (~/.config/fiken-api/):
~/.config/fiken-api/credentials.json with account(s)~/.config/fiken-api/client.mjsgetFikenClient(accountName)fiken.getContacts()Step 4: Initialize number series
https://fiken.no/foretak/{slug}/fakturautkast/nyStep 5: Verify
getContacts() to confirm the token works403 Forbidden: API module not activated (Fiken > Foretak > Tilleggstjenester)401 Unauthorized: Bad token (regenerate at Fiken > Innstillinger > API)| Function | Description |
|---|---|
isFikenConfigured() | Check if env vars are set |
getContacts() | List all contacts |
findContactByOrgNumber(orgNr) | Find contact by Norwegian org number |
createContact(input) | Create customer/supplier — returns contactId |
getInvoices(page, pageSize) | List invoices (paginated) |
getInvoice(id) | Get single invoice |
createInvoiceDraft(input) | Create draft — returns { draftId, uuid, draftUrl } |
sendInvoiceDraft(draftId, sendInput) | Two-step: finalize + dispatch — returns { invoiceId, saleId, invoiceUrl } |
isInvoiceSettled(id) | Check if invoice is paid |
getProducts() | List products/services |
getAccounts() | Chart of accounts (~475 accounts) |
getBankAccounts() | Bank accounts |
nokToOre(nok) / oreToNok(ore) | Currency conversion (1 NOK = 100 ore) |
delay(ms) | Rate limit helper (default 250ms) |
require('dotenv').config();
const fiken = require('./skills/fiken/scripts/client');
// 1. Find or create contact
let contact = await fiken.findContactByOrgNumber('999888777');
if (!contact) {
const contactId = await fiken.createContact({
name: 'Example Company AS',
email: '[email protected]',
organizationNumber: '999888777',
address: {
streetAddress: 'Storgata 1',
city: 'Oslo',
postCode: '0001',
country: 'NO'
},
customer: true,
supplier: false
});
contact = { contactId };
}
// 2. Create invoice draft
const draft = await fiken.createInvoiceDraft({
type: 'invoice', // REQUIRED — see gotcha #5
issueDate: '2026-03-01',
daysUntilDueDate: 14,
customerId: contact.contactId,
ourReference: 'Your Name',
yourReference: 'Their Contact',
orderReference: 'PO-2026-001', // Optional — for EHF routing
invoiceText: 'Consulting services — March 2026',
currency: 'NOK',
// bankAccountNumber is auto-included by the client
lines: [{
description: 'Consulting — project planning, 8 hours',
quantity: 8,
unitPrice: fiken.nokToOre(1500), // NOK 1,500/hr = 150000 ore
vatType: 'HIGH', // 25% MVA (use 'OUTSIDE' if not MVA-registered)
incomeAccount: '3020' // Services, high MVA (use '3220' if not MVA-registered)
}]
});
console.log('Draft URL:', draft.draftUrl);
// 3. Finalize + send as EHF (two-step process handled by the client)
await fiken.delay(500);
const invoice = await fiken.sendInvoiceDraft(draft.draftId, {
method: ['ehf'],
includeDocumentAttachments: true
});
console.log('Invoice ID:', invoice.invoiceId); // Same as draftId
console.log('Sale ID:', invoice.saleId); // Different — used for dashboard URLs
console.log('Invoice URL:', invoice.invoiceUrl); // Uses saleIdAre you MVA-registered? This determines which vatType and income account to use.
| Scenario | vatType | Income Account | Account Name |
|---|---|---|---|
| MVA-registered, standard rate | HIGH | 3020 | Tjenester, hoy mva-sats (25%) |
| MVA-registered, food/drink | MEDIUM | Account varies | 15% rate |
| MVA-registered, zero-rated | EXEMPT | 3120 | Tjenester, fritatt for mva |
| Not MVA-registered | `OUTSIDE` | `3220` | Tjenester, unntatt for mva |
Critical distinction:
3120, EXEMPT) = zero-rated, company IS in the MVA system but rate is 0%3220, OUTSIDE) = exempt, company is NOT in the MVA system at allFull VAT reference with all types and account compatibility: see references/vat-guide.mdvatType and incomeAccount are linked. Using incompatible pairs returns 400. See the table above for correct combinations.
This is YOUR bank account number (the invoice sender's) — the "pay to" account printed on the invoice. It is NOT the customer's account.
The client auto-fetches it from GET /companies/{slug}/bankAccounts (picks first active account, caches in memory). If calling the API directly, you must include bankAccountNumber (Norwegian format, not IBAN). Without it: 500: "Kontonummer mangler på faktura". The API returns [{ bankAccountNumber, inactive }] — pick first where inactive === false.
The very first invoice/credit note/offer MUST be created in the Fiken web UI to establish the number series. After that, the API works. Error: 400: "Missing number series for drafts of type: invoice.".
All monetary amounts use ore. NOK 4,998 → 499800. Use fiken.nokToOre() and fiken.oreToNok().
type field is REQUIRED on draftsValues: invoice, cash_invoice, offer, order_confirmation, credit_note. Omitting returns: 400: "'type' er påkrevd".
Contact and product updates via PUT replace the entire resource. Always include all fields. The only PATCH is on invoices: newDueDate and sentManually only.
Once sent, you can only change newDueDate and sentManually. To fix line items, issue a credit note and create a new invoice.
Step 1: POST /invoices/drafts/{draftId}/createInvoice — NO body, just finalizes. Step 2: POST /invoices/send — dispatches (EHF/email/auto). Without Step 2, the invoice exists but was never sent. If you pass send params to Step 1, they are silently ignored.
invoiceId (API operations) vs sale.saleId (dashboard URLs) vs sale.transactionId (accounting). draftId = invoiceId after finalization. The Location header from createInvoice returns saleId, NOT invoiceId.
Finalized invoice URL: /foretak/{slug}/handel/salg/{saleId} — NOT /faktura/{invoiceId}.
The send request field is recipientEmail. Using emailAddress is silently ignored.
All gotchas with error messages and solutions: see references/gotchas.md| Method | When to use |
|---|---|
['ehf'] | B2B to Norwegian companies (preferred) |
['email'] | Direct email delivery (requires recipientEmail) |
['efaktura'] | Norwegian consumer e-invoice via bank |
['sms'] | SMS delivery (requires mobileNumber) |
['letter'] | Physical letter (extra charge, Norway only) |
['auto'] | Fiken picks: EHF > eFaktura > SMS > Email |
Multiple methods = priority list: ['sms', 'email'] tries SMS first, falls back to email.
Full sendInvoiceRequest:
{
invoiceId: 12345, // Required
method: ['ehf'], // Required — array of strings
includeDocumentAttachments: true, // Required
recipientName: 'Name', // Optional
recipientEmail: '[email protected]', // Optional (for email method)
emailSendOption: 'auto', // 'document_link' | 'attachment' | 'auto'
mergeInvoiceAndAttachments: false, // Merge into single PDF
organizationNumber: '999888777', // Optional (for EHF)
mobileNumber: '12345678', // Optional (for SMS)
message: 'Additional message text' // Optional — included in email/notification
}Draft: https://fiken.no/foretak/{slug}/fakturautkast/{uuid}
Invoice: https://fiken.no/foretak/{slug}/handel/salg/{saleId}
Contact: https://fiken.no/foretak/{slug}/kontakt/{contactId}
Credit Note: https://fiken.no/foretak/{slug}/kreditnota/{creditNoteId}fiken.no (NOT app.fiken.no)fakturautkast (ONE word)invoice.sale.saleId), NOT invoiceIdsale.saleId| Header | Description |
|---|---|
Fiken-Api-Page | Current page (0-indexed) |
Fiken-Api-Page-Size | Items per page |
Fiken-Api-Page-Count | Total pages |
Fiken-Api-Result-Count | Total results |
Default: page=0, pageSize=25. Maximum: pageSize=100.
Drafts and products can be safely created and immediately deleted (204). This enables testing without permanent changes:
const draft = await fiken.createInvoiceDraft({ /* ... */ });
// inspect draft...
// DELETE /companies/{slug}/invoices/drafts/{draftId} → 204https://api.fiken.no/api/v2Authorization: Bearer {FIKEN_API_TOKEN}application/json onlyyyyy-MM-dd format.png, .jpeg, .jpg, .gif, .pdf only| File | Contents |
|---|---|
references/api-endpoints.md | All ~110 endpoints organized by category |
references/workflows.md | Multi-line invoices, credit notes, offers, products, contacts, payments |
references/gotchas.md | All 14 gotchas with error messages and solutions |
references/vat-guide.md | Complete VAT types, account matrix, MVA explanation |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.