Skip to content

Step-by-Step Integration

This guide walks you through the complete process of integrating the fiskaly SIGN SE API for Swedish fiscal compliance, using a combination of the fiskaly HUB and API requests. By the end, you will have a fully working System with Records being signed and registered with the Swedish TCS (Tax Compliance System).

Before diving into the setup, here is what you will configure:

🏢

Organization


  • AccountHUB-generated

    Top-level entity in fiskaly HUB. Cannot be nested inside another Account.

  • GroupHUB-generated

    Intermediate layer organizing Units into logical clusters (e.g. one per country).

  • UnitAPI-generated

    Merchant / Taxpayer operating within the Group.

🔑

API Key & Secret


  • Group levelHUB-generated

    Generated in HUB for the Organization GROUP. Used to authenticate in the SIGN SE API to create Organization Units and their API Keys.

  • Unit levelAPI-generated

    Generated via API (createSubject endpoint) for the Organization UNIT. Used to authenticate for all unit-level operational calls.

🧾

Taxpayer


Entity registered with the Swedish Tax Agency (Skatteverket) and subject to Swedish cash register regulations (SFS 2007:592).

  • COMPANY

    Legal entity (aktiebolag, handelsbolag, etc.)

  • INDIVIDUAL

    Natural person (enskild firma)

📍

Location


  • HEAD_OFFICE

    Auto-created on Taxpayer creation, shares the same UUID. Coincides with the legal address.

  • BRANCH

    Each shop, store, or other operational business location where the cash register (kassaregister) is physically located.

💻

System


  • FISCAL_DEVICE

    Abstraction of a cash register. Commissioning enrolls the system and generates the unique 16-character tillverkningsnummer.

📄

Record


Each business operation carried out in the System. Requires two subsequent calls:

  • INTENTION

    Identifies the intention to record a transaction in the System.

  • TRANSACTION

    The fiscal receipt sent to TCS for signing. Returns a control code (avstämningskod) on success.

You will also need a tool to make HTTP requests — for example cURL (command line), Postman, or your own application code.

The diagram below illustrates the workflow and highlights the essential steps necessary to successfully complete your integration.

  1. Register on HUB

    Begin by registering on the fiskaly HUB.

    Creating a fiskaly Account is the first step, after which you can proceed with setting up the first organizational structure for your business and generating your API Key.

  2. Create Account & Group

    Continue with creating your Account and first Group using the HUB. In the SIGN SE API, the GROUP is a required intermediate layer within your ACCOUNT, used to organize your UNIT organizations.

  3. Create API Key

    The next step is to generate an API Key for your organization via the HUB. This API Key and Secret pair is required to create your Organization(s) of type UNIT (Step 5).

    Starting from the next step, you will be utilizing our SIGN SE API.

  1. Create Token (Management)

    Begin using the SIGN SE API through the createToken endpoint. You will need to create a token to authenticate for the next steps.

    curl -X POST https://test.api.fiskaly.com/api/v1/auth/token \
      -H "Content-Type: application/json" \
      -d '{
        "api_key": "YOUR_API_KEY",
        "api_secret": "YOUR_API_SECRET"
      }'
    Example response (200 OK)
    {
    "content": {
    "id": "tok_abc123",
    "authentication": {
    "type": "JWT",
    "bearer": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_at": "2026-03-02T12:00:00Z"
    },
    "organization": {
    "id": "YOUR_GROUP_ORG_ID"
    },
    "subject": {
    "id": "sub_abc123"
    }
    },
    "metadata": {
    "trace_identifier": "trace_abc123"
    }
    }
  2. Create Organization UNIT

    Continue with creating an Organization of type UNIT through the createOrganization endpoint. You will need to create one Organization UNIT for each of your taxpayer representations.

    When creating an Organization of type UNIT, ensure it is associated to the Organization of type GROUP you previously created via the HUB. To do this, use the token generated from the API keys created for your Organization of type GROUP. This reflects the hierarchical structure where the Organization of type UNIT is nested under your Organization of type GROUP.

    curl -X POST https://test.api.fiskaly.com/api/v1/organizations \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID" \
      -H "X-Scope-Identifier: YOUR_GROUP_ORG_ID" \
      -d '{
        "type": "UNIT",
        "name": "My UNIT Organization",
        "parent_id": "YOUR_GROUP_ORG_ID"
      }'
    Example response (201 Created)
    {
    "content": {
    "id": "org_unit_abc123",
    "state": "ENABLED",
    "type": "UNIT",
    "name": "My UNIT Organization",
    "organization": {
    "id": "YOUR_GROUP_ORG_ID"
    }
    },
    "metadata": {
    "trace_identifier": "trace_abc123"
    }
    }
  3. Create Subject API Key

    Create a Subject of type API_KEY through the createSubject endpoint. The connection between the Organization of type UNIT and the API Key is established via the X-Scope-Identifier (using the id of the newly created Organization).

    curl -X POST https://test.api.fiskaly.com/api/v1/subjects \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "API_KEY"
      }'
    Example response (201 Created)
    {
    "content": {
    "id": "sub_abc123",
    "state": "ENABLED",
    "type": "API_KEY",
    "credentials": {
    "api_key": "fsk_unit_abc123",
    "api_secret": "secret_only_shown_once"
    }
    },
    "metadata": {
    "trace_identifier": "trace_abc123"
    }
    }
  4. Create Token (UNIT)

    Next, create a token that will be used to create resources within the corresponding Organization of type UNIT.

    curl -X POST https://test.api.fiskaly.com/api/v1/auth/token \
      -H "Content-Type: application/json" \
      -d '{
        "api_key": "YOUR_UNIT_API_KEY",
        "api_secret": "YOUR_UNIT_API_SECRET"
      }'
    Example response (200 OK)
    {
    "content": {
    "id": "tok_unit_abc123",
    "authentication": {
    "type": "JWT",
    "bearer": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_at": "2026-03-02T12:00:00Z"
    },
    "organization": {
    "id": "org_unit_abc123"
    },
    "subject": {
    "id": "sub_abc123"
    }
    },
    "metadata": {
    "trace_identifier": "trace_abc123"
    }
    }
  5. Create Taxpayer

    Now you’re ready to create the operational parts required for fiscalization in Sweden. Use the createTaxpayer endpoint to create the representation of a taxpayer:

    • Set the Taxpayer as type COMPANY (legal entity) or INDIVIDUAL (natural person). In both cases, the name and address must be provided.
    • Within the Swedish fiscalization information, provide:
      • type: "SE" — identifies the Swedish fiscalization scheme
      • tax_id_number: Swedish organisation number (organisationsnummer, 10 digits) or personal identity number (personnummer, 12 digits) registered with Skatteverket

    Once created, the Taxpayer state is set to ACQUIRED. Update it to COMMISSIONED using the updateTaxpayer endpoint.

    # Create Taxpayer
    curl -X POST https://test.api.fiskaly.com/api/v1/taxpayers \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "COMPANY",
        "name": "Min Butik AB",
        "address": {
          "street": "Storgatan 1",
          "postal_code": "111 23",
          "city": "Stockholm",
          "country_code": "SE"
        },
        "fiscalization": {
          "type": "SE",
          "tax_id_number": "5561234567"
        }
      }'
    
    # Commission Taxpayer
    curl -X PATCH https://test.api.fiskaly.com/api/v1/taxpayers/YOUR_TAXPAYER_ID \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "state": "COMMISSIONED"
      }'
  6. Create Location

    For each operating business location, create a Location of type BRANCH via the createLocation endpoint. This address will be used for the cash register registration with Skatteverket.

    Once created, the Location state is set to ACQUIRED. Update it to COMMISSIONED using the updateLocation endpoint.

    # Create Location
    curl -X POST https://test.api.fiskaly.com/api/v1/locations \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "BRANCH",
        "address": {
          "street": "Storgatan 1",
          "postal_code": "111 23",
          "city": "Stockholm",
          "country_code": "SE"
        }
      }'
    
    # Commission Location
    curl -X PATCH https://test.api.fiskaly.com/api/v1/locations/YOUR_LOCATION_ID \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "state": "COMMISSIONED"
      }'
  7. Create System

    The createSystem endpoint allows you to create an abstraction of every device you use to issue receipts. Each cash register or POS needs to be provided as a new System of type FISCAL_DEVICE.

    • A System will be connected to a specific, previously created Location of type BRANCH.
    • Provide producer details (MPN type, number, and product name/brand) and software information (name and version) as top-level fields.

    Once created, the System state is set to ACQUIRED. Update it to COMMISSIONED using the updateSystem endpoint. Commissioning triggers enrollment, which generates the unique 16-character tillverkningsnummer and binds the POS to the signing service.

    # Create System
    curl -X POST https://test.api.fiskaly.com/api/v1/systems \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "FISCAL_DEVICE",
        "location": "YOUR_LOCATION_ID",
        "producer": {
          "type": "MPN",
          "number": "POS-1000",
          "details": {
            "name": "My POS Terminal",
            "brand": "My POS Brand"
          }
        },
        "software": {
          "name": "My POS Software",
          "version": "1.0.0"
        }
      }'
    
    # Commission System (triggers TCS enrollment)
    curl -X PATCH https://test.api.fiskaly.com/api/v1/systems/YOUR_SYSTEM_ID \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "state": "COMMISSIONED"
      }'
    
    # Retrieve compliance artifact (tillverkningsnummer)
    curl -X GET "https://test.api.fiskaly.com/api/v1/records/YOUR_RECORD_ID?compliance-artifact" \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID"
  8. Startup Check (INTENTION::OPENING)

    Before issuing any receipts, the POS must perform a mandatory startup check. This verifies system enrollment and signing service connectivity.

    Send an INTENTION::OPENING record at every POS startup. The response includes the system status — the POS must only proceed to sales mode if STATUS_OK is returned.

    # Startup check — INTENTION::OPENING
    curl -X POST https://test.api.fiskaly.com/api/v1/records \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "INTENTION::OPENING",
        "system_id": "YOUR_SYSTEM_ID"
      }'

    At the end of the business day, send an INTENTION::CLOSING record to mark the register as closed:

    # End of day — INTENTION::CLOSING
    curl -X POST https://test.api.fiskaly.com/api/v1/records \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "INTENTION::CLOSING",
        "system_id": "YOUR_SYSTEM_ID"
      }'
  9. Create Record

    Creating a Record in SIGN SE requires two subsequent calls:

    • Part A) INTENTION — at the beginning of the sale process
    • Part B) TRANSACTION — after the payment process

    The TRANSACTION payload requires:

    • entries — each item with per-entry VAT information using VAT_RATE type (with code, percentage, amount, exclusive, inclusive) or VAT_EXEMPTION type (with an exemption code)
    • breakdown — a VAT breakdown array with one entry per VAT rate used in the transaction
    • totals — transaction-level VAT totals (amount, exclusive, inclusive)
    • payments — at least one payment method
    # Part A) Create Record — INTENTION
    curl -X POST https://test.api.fiskaly.com/api/v1/records \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID_1" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "INTENTION::TRANSACTION",
        "system_id": "YOUR_SYSTEM_ID"
      }'
    
    # Part B) Create Record — TRANSACTION (RECEIPT)
    curl -X POST https://test.api.fiskaly.com/api/v1/records \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -H "X-Idempotency-Key: YOUR_UNIQUE_UUID_2" \
      -H "X-Scope-Identifier: YOUR_UNIT_ORG_ID" \
      -d '{
        "type": "TRANSACTION::RECEIPT",
        "intention_id": "YOUR_INTENTION_RECORD_ID",
        "document": {
          "number": "K-2026-0001"
        },
        "entries": [
          {
            "type": "SALE",
            "data": {
              "type": "ITEM",
              "text": "Product A",
              "unit": { "type": "PIECE", "quantity": "1.00" },
              "value": { "amount": "100.00" },
              "vat": {
                "type": "VAT_RATE",
                "code": "STANDARD",
                "percentage": "25.00",
                "amount": "25.00",
                "exclusive": "100.00",
                "inclusive": "125.00"
              }
            },
            "details": { "concept": "GOODS" }
          }
        ],
        "breakdown": [
          {
            "type": "VAT_RATE",
            "code": "STANDARD",
            "percentage": "25.00",
            "amount": "25.00",
            "exclusive": "100.00",
            "inclusive": "125.00"
          }
        ],
        "totals": {
          "vat": {
            "amount": "25.00",
            "exclusive": "100.00",
            "inclusive": "125.00"
          }
        },
        "payments": [
          { "type": "CASH", "amount": "125.00" }
        ],
        "details": {
          "creators": [{ "type": "CASHIER", "name": "Anna" }]
        }
      }'

    Once the record is properly created, the data is sent to the TCS which returns a control code (avstämningskod) that must be printed on the customer receipt.

Was this page helpful?