Files
fiken-api/README.md
T
ringe e92be347b2
CI / test (3.1) (push) Successful in 1m22s
CI / test (3.2) (push) Successful in 33s
CI / test (3.3) (push) Successful in 33s
Add README with auth, usage, pagination, uploads, and error-handling examples
2026-05-29 15:01:24 +02:00

5.1 KiB

Fiken

A resource-oriented Ruby client for the Fiken API v2 — the Norwegian accounting and invoicing platform.

  • Personal API token and OAuth2 (authorization-code) authentication
  • Resource-oriented surface that mirrors the API (client.invoices(slug).drafts.create(...))
  • Automatic pagination with auto_paging_each
  • HTTP errors mapped to typed exceptions, with retry on rate limits (429) and server errors

Installation

# Gemfile
gem "fiken"
bundle install

Authentication

Personal API token

Generate a token in Fiken (under your account settings) and pass it in:

client = Fiken::Client.new(token: ENV["FIKEN_TOKEN"])
client.user            # => #<Fiken::Object name="..." email="...">
client.companies.list  # => #<Fiken::Collection ...>

OAuth2 (acting on behalf of other Fiken users)

oauth = Fiken::OAuth.new(
  client_id:     ENV["FIKEN_CLIENT_ID"],
  client_secret: ENV["FIKEN_CLIENT_SECRET"],
  redirect_uri:  "https://example.com/oauth/callback"
)

# 1. Send the user to authorize
redirect_to oauth.authorize_url(state: "csrf-token")

# 2. In your callback, exchange the code for tokens
token  = oauth.exchange_code(params[:code])
client = Fiken::Client.new(access_token: token.access_token)

# 3. Later, refresh
token = oauth.refresh(token.refresh_token)

Usage

Almost every resource is scoped to a company, identified by its slug:

slug = client.companies.list.first.slug

Reading

client.contacts(slug).list(page: 0, pageSize: 50)
client.contacts(slug).find(123)
client.invoices(slug).find(456)
client.accounts(slug).find("1500:10001")

Pagination

A list returns a Fiken::Collection that exposes the page metadata and can walk every page lazily:

contacts = client.contacts(slug).list
contacts.result_count            # total across all pages
contacts.auto_paging_each do |contact|
  puts contact.name
end

Creating and updating

# Create returns the new resource's id (parsed from the Location header)
created = client.contacts(slug).create(name: "Acme AS", organizationNumber: "123456789")
created.id

# Contacts/drafts update via PUT; finalized invoices/projects/etc. via PATCH
client.contacts(slug).update(123, email: "post@acme.no")
client.invoices(slug).update(456, sentManually: true)
client.contacts(slug).delete(123)

Invoices, credit notes, offers, order confirmations

These share a draft → finalize lifecycle, plus counters and (where supported) sending:

invoices = client.invoices(slug)

draft = invoices.drafts.create(
  type: "invoice",
  customerId: 123,
  lines: [{ description: "Consulting", unitPrice: 100_000, vatType: "HIGH", quantity: 1 }]
)
invoice = invoices.drafts.create_document(draft.id)   # finalize the draft

invoices.dispatch(invoiceId: invoice.id, method: ["email"], includeDocumentAttachments: true)
invoices.counter                                       # current invoice number
invoices.create_counter(value: 1000)                   # initialize it

client.credit_notes(slug).create_full(invoiceId: invoice.id)

Sales, purchases and payments

sales = client.sales(slug)
sales.create(saleNumber: "1", date: "2026-01-01", kind: "external_invoice", lines: [...])
sales.payments(5).create(date: "2026-01-05", account: "1920:10001", amount: 125_000)
sales.settle(5, settledDate: "2026-01-10")
sales.write_off(5)
sales.delete(5, description: "duplicate")

Attachments and the inbox (file uploads)

client.invoices(slug).attachments(456).add(path: "invoice.pdf")
client.invoices(slug).attachments(456).add(io: pdf_io, filename: "invoice.pdf",
                                            content_type: "application/pdf")
client.inbox(slug).create(path: "receipt.pdf", name: "Office supplies")

Error handling

Non-success responses raise a typed subclass of Fiken::Error, each carrying #status and #body:

begin
  client.invoices(slug).find(999_999)
rescue Fiken::NotFound => e
  e.status   # => 404
rescue Fiken::RateLimited
  # retried automatically first; raised only if retries are exhausted
rescue Fiken::Error => e
  warn e.message
end

BadRequest (400), Unauthorized (401), Forbidden (403), NotFound (404), UnprocessableEntity (422), RateLimited (429) and ServerError (5xx) are all provided.

Available resources

user, companies, accounts, account_balances, bank_accounts, bank_balances, contacts (+ contact_persons), groups, products, journal_entries, transactions, invoices, credit_notes, offers, order_confirmations, sales, purchases, inbox, projects, activities, time_entries, time_users.

Configuration

Fiken::Client.new(
  token:         ENV["FIKEN_TOKEN"],
  base_url:      "https://api.fiken.no/api/v2", # default
  user_agent:    "my-app/1.0",
  retry_options: { max: 3 },                    # passed to faraday-retry
  logger:        Logger.new($stdout)
)

Development

bin/setup        # or: bundle install
bundle exec rspec
bundle exec rubocop

License

The gem is available as open source under the terms of the MIT License.