> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chift.eu/llms.txt
> Use this file to discover all available pages before exploring further.

# Procountor

> Connect Procountor to your product through Chift's unified Accounting API.

export const CoverageIframe = ({api = 'accounting', connectors}) => {
  const [theme, setTheme] = React.useState('light');
  const [isFullscreen, setIsFullscreen] = React.useState(false);
  const [currentIframeUrl, setCurrentIframeUrl] = React.useState(null);
  const iframeRef = React.useRef(null);
  React.useEffect(() => {
    const checkTheme = () => {
      const isDark = document.documentElement.classList.contains('dark');
      setTheme(isDark ? 'dark' : 'light');
    };
    checkTheme();
    const observer = new MutationObserver(checkTheme);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => observer.disconnect();
  }, []);
  React.useEffect(() => {
    const handleFullscreenChange = () => {
      setIsFullscreen(!!document.fullscreenElement);
    };
    document.addEventListener('fullscreenchange', handleFullscreenChange);
    return () => document.removeEventListener('fullscreenchange', handleFullscreenChange);
  }, []);
  React.useEffect(() => {
    const handleMessage = event => {
      if (!event.origin.includes('chift-coverage-matrix.s3.eu-west-3.amazonaws.com')) return;
      if (event.data?.type === 'urlChange' && event.data?.url) {
        setCurrentIframeUrl(event.data.url);
      }
    };
    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, []);
  const queryParams = new URLSearchParams({
    api,
    theme,
    ...connectors ? {
      connectors
    } : {}
  });
  const iframeUrl = `https://chift-coverage-matrix.s3.eu-west-3.amazonaws.com/coverage.html?${queryParams.toString()}`;
  const openUrl = currentIframeUrl || iframeUrl;
  const toggleFullscreen = () => {
    if (!document.fullscreenElement) {
      iframeRef.current?.requestFullscreen();
    } else {
      document.exitFullscreen();
    }
  };
  const isDark = theme === 'dark';
  const buttonStyle = {
    display: 'inline-flex',
    alignItems: 'center',
    gap: '8px',
    padding: '4px 12px',
    fontSize: '14px',
    fontWeight: '500',
    color: isDark ? '#d4d4d4' : '#374151',
    backgroundColor: 'transparent',
    border: `1px solid ${isDark ? '#404040' : '#e5e7eb'}`,
    borderRadius: '12px',
    cursor: 'pointer',
    textDecoration: 'none',
    transition: 'all 0.15s ease'
  };
  const hoverBg = isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.03)';
  const hoverBorder = isDark ? '#525252' : '#d1d5db';
  const defaultBg = 'transparent';
  const defaultBorder = isDark ? '#404040' : '#e5e7eb';
  return <>
  <div style={{
    display: 'flex',
    justifyContent: 'flex-end',
    gap: '12px',
    marginBottom: '8px'
  }}>
    <button onClick={toggleFullscreen} style={buttonStyle} onMouseEnter={e => {
    e.target.style.backgroundColor = hoverBg;
    e.target.style.borderColor = hoverBorder;
  }} onMouseLeave={e => {
    e.target.style.backgroundColor = defaultBg;
    e.target.style.borderColor = defaultBorder;
  }}>
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        {isFullscreen ? <>
            <polyline points="4 14 10 14 10 20"></polyline>
            <polyline points="20 10 14 10 14 4"></polyline>
            <line x1="14" y1="10" x2="21" y2="3"></line>
            <line x1="3" y1="21" x2="10" y2="14"></line>
          </> : <>
            <polyline points="15 3 21 3 21 9"></polyline>
            <polyline points="9 21 3 21 3 15"></polyline>
            <line x1="21" y1="3" x2="14" y2="10"></line>
            <line x1="3" y1="21" x2="10" y2="14"></line>
          </>}
      </svg>
      {isFullscreen ? 'Exit Fullscreen' : 'Fullscreen'}
    </button>
    <a href={iframeUrl} target="_blank" rel="noopener noreferrer" style={buttonStyle} onMouseEnter={e => {
    e.target.style.backgroundColor = hoverBg;
    e.target.style.borderColor = hoverBorder;
  }} onMouseLeave={e => {
    e.target.style.backgroundColor = defaultBg;
    e.target.style.borderColor = defaultBorder;
  }}>
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
        <polyline points="15 3 21 3 21 9"></polyline>
        <line x1="10" y1="14" x2="21" y2="3"></line>
      </svg>
      Open in new tab
    </a>
  </div>
  <iframe ref={iframeRef} src={iframeUrl} title={`Chift Coverage Matrix - ${api}`} style={{
    height: 'max(500px, 80vh)'
  }} className="w-full" allowFullScreen />
  <blockquote>
    <p>
      <strong>Matrix Legend 🧭</strong>
    </p>
    <table>
      <thead>
        <tr>
          <th>Status</th>
          <th>Meaning</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>✅ Implemented</td>
          <td>Endpoint is implemented and available.</td>
        </tr>
        <tr>
          <td>❌ Not supported</td>
          <td>
            Endpoint is not supported by the target software (connector
            limitation). Cannot be implemented.
          </td>
        </tr>
        <tr>
          <td>💬 On request</td>
          <td>
            Endpoint is not implemented but feasibility is validated. Can be
            implemented on request — contact your Chift point of contact to
            discuss scope and timing.
          </td>
        </tr>
        <tr>
          <td>🔎 To be analyzed</td>
          <td>
            Endpoint is not implemented and feasibility has not yet been fully
            assessed. Analysis is pending.
          </td>
        </tr>
      </tbody>
    </table>
  </blockquote>
</>;
};

export const OverviewLegend = ({showTitle = true}) => <blockquote>
    {showTitle && <p>
        <strong>Overview legend 🧭</strong>
      </p>}
    <table>
      <thead>
        <tr>
          <th>Column</th>
          <th>Value</th>
          <th>Meaning</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Geography</td>
          <td>🇫🇷 FR · 🇧🇪 BE · …</td>
          <td>Countries where the connector is officially supported.</td>
        </tr>
        <tr>
          <td rowSpan={3}>Software type</td>
          <td>SaaS</td>
          <td>Through API.</td>
        </tr>
        <tr>
          <td>On-premise (local agent)</td>
          <td>
            Software running locally — installation of a local agent is
            required.
          </td>
        </tr>
        <tr>
          <td>On-premise (API)</td>
          <td>Software running locally — API available.</td>
        </tr>
        <tr>
          <td rowSpan={2}>Status</td>
          <td>🔵 Live</td>
          <td>Connector is generally available and production-ready.</td>
        </tr>
        <tr>
          <td>🟣 Beta</td>
          <td>
            Connector is in beta — usable in production but may still evolve.
          </td>
        </tr>
        <tr>
          <td>Multi folder</td>
          <td>✅ Yes / ❌ No</td>
          <td>
            Connection to multiple accounting folders at the same time (see{' '}
            <a href="/unified-apis/accounting/concepts/folder">
              accounting folders guide
            </a>
            ).
          </td>
        </tr>
        <tr>
          <td>Rate limits</td>
          <td>✅ No / ❌ Yes</td>
          <td>Whether the target software sets rate limits on API calls.</td>
        </tr>
        <tr>
          <td rowSpan={3}>API keys</td>
          <td>❎ No</td>
          <td>
            No API keys required (OAuth2 client secret and client ID). No
            requirements to activate the connector — you can create a
            connection.
          </td>
        </tr>
        <tr>
          <td>🔑</td>
          <td>
            Keys are required to activate the connector. Chift cannot act as
            intermediary to obtain them; we can still assist with steps to get
            keys directly from the software provider.
          </td>
        </tr>
        <tr>
          <td>🔑 ☑️ via Chift</td>
          <td>
            Keys are required to activate the connector. You can go through
            Chift to get the keys (intermediary or partnership keys). An
            approval process may still apply, but you do not need to request
            keys from the vendor on your own.
          </td>
        </tr>
        <tr>
          <td rowSpan={3}>Approval / certification process</td>
          <td>⚡ Instant</td>
          <td>
            No keys required, or Chift can encode their keys for you when
            requested. Activation is instantaneous.
          </td>
        </tr>
        <tr>
          <td>🟢 Approval</td>
          <td>
            Approval will be granted. The vendor may require information or app
            configuration in a developer portal before issuing keys.
          </td>
        </tr>
        <tr>
          <td>🟠 Approval</td>
          <td>
            Approval is not guaranteed — often due to integration strategy; the
            vendor may do a deeper assessment (competitors, partnership
            requirements, and similar).
          </td>
        </tr>
        <tr>
          <td rowSpan={2}>Activation lead time</td>
          <td>⚡ Instant</td>
          <td>
            If no keys are required, or Chift has keys ready to share with you.
          </td>
        </tr>
        <tr>
          <td>Time</td>
          <td>
            Estimated time to get the connector activated in production as a
            result of the approval or certification process (e.g. ⏱️ 2 days, 1
            week).
          </td>
        </tr>
        <tr>
          <td rowSpan={3}>Extra fees — software editor</td>
          <td>❎ No</td>
          <td>No fees charged by the software editor.</td>
        </tr>
        <tr>
          <td>💰 🕹️</td>
          <td>Fees associated with obtaining a testing account.</td>
        </tr>
        <tr>
          <td>💰 🔑</td>
          <td>Fees charged to get API keys.</td>
        </tr>
        <tr>
          <td rowSpan={2}>Extra fees — end-user</td>
          <td>❎ No</td>
          <td>The end-user does not pay extra to get integrated.</td>
        </tr>
        <tr>
          <td>💰 Yes</td>
          <td>The end-user must pay extra to get integrated.</td>
        </tr>
        <tr>
          <td>Comments on costs</td>
          <td>—</td>
          <td>Additional notes on fees or pricing when relevant.</td>
        </tr>
        <tr>
          <td rowSpan={4}>Sandbox account</td>
          <td>✅ via Chift</td>
          <td>Chift can provide you with a sandbox.</td>
        </tr>
        <tr>
          <td>🟠 Only through integrator</td>
          <td>Only the software's integrator can provide a sandbox.</td>
        </tr>
        <tr>
          <td>✅ Self-service</td>
          <td>You can create your own sandbox.</td>
        </tr>
        <tr>
          <td>✅ Trial account</td>
          <td>It is possible to create a trial account.</td>
        </tr>
      </tbody>
    </table>
  </blockquote>;

export const ConnectorCardIframe = ({api = 'accounting', connectors}) => {
  const [theme, setTheme] = React.useState('light');
  React.useEffect(() => {
    const checkTheme = () => {
      const isDark = document.documentElement.classList.contains('dark');
      setTheme(isDark ? 'dark' : 'light');
    };
    checkTheme();
    const observer = new MutationObserver(checkTheme);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => observer.disconnect();
  }, []);
  const queryParams = new URLSearchParams({
    api,
    theme,
    ...connectors ? {
      connectors
    } : {}
  });
  const iframeUrl = `https://chift-coverage-matrix.s3.eu-west-3.amazonaws.com/connector-card.html?${queryParams.toString()}`;
  return <iframe src={iframeUrl} title={`Chift connector information - ${api}`} style={{
    display: 'block',
    width: '100%',
    height: '480px',
    margin: 0,
    padding: 0,
    border: 'none'
  }} />;
};

<ConnectorCardIframe api="accounting" connectors="Procountor" />

<Accordion title="Overview Legend 🧭">
  <OverviewLegend showTitle={false} />
</Accordion>

[📊 See what this connector supports ↓](#coverage)

## Introduction

Procountor is a Finnish cloud accounting and financial management software covering bookkeeping, invoicing, payments and payroll. The connector supports Procountor companies in Finland and Sweden.

## Activate Procountor

### Partner keys

You'll need your own developer account, registered with Procountor.

Procountor issues one API client (a client ID and a client secret) per integration. You can request it yourself, or ask your Chift point of contact to file the request with Procountor for you.

Procountor reviews every request and can refuse it. It publishes no criteria, and may ask for an interview about your integration first. In our experience, allow about a week.

<Steps>
  <Step title="Register as a developer">
    Register on Procountor's [developer site](https://dev.procountor.com/getting-started/). For questions, Procountor's integration team answers at `integrations@procountor.com`.
  </Step>

  <Step title="Test with the test company">
    Procountor gives you a test company on its test server, with a client ID and a client secret for it. See *Test Procountor* below.
  </Step>

  <Step title="Request production access">
    When your integration is ready, fill in Procountor's [production access form](https://dev.procountor.com/contact/request-production-access/). Procountor then issues your production client ID and client secret.
  </Step>
</Steps>

<Card title="Activate Procountor in your Chift account" icon="bolt" href="https://chift.app/connectors" horizontal>
  In **Connectors**, enter your **Client ID** and **Client secret**.
</Card>

### Connector settings

<Frame>
  <img src="https://mintcdn.com/chift/JlVKaqc6aeAYrOdY/images/connectors/procountor/procountor-1.png?fit=max&auto=format&n=JlVKaqc6aeAYrOdY&q=85&s=b6c231f27e3ddd47799677d27cfc7e4b" alt="The Environment setting in the Chift connector settings for Procountor, set to Sandbox" width="1375" height="175" data-path="images/connectors/procountor/procountor-1.png" />
</Frame>

**Environment** selects the Procountor server Chift connects to.

* **Production** (default): Procountor's production server.
* **Sandbox**: Procountor's test server (PTS).

Choose **Sandbox** while you test with your test company, and enter the client ID and client secret of that test company: production credentials do not work on the test server. End users then create their API key in Procountor's test environment: a production key does not work on the test server, and a test key does not work in production.

## Test Procountor

| | |
| - | - |
| **Environment** | A test company on Procountor's test server (PTS), separate from production, with two-factor login |
| **How to get it** | Register as a developer on Procountor's [developer site](https://dev.procountor.com/getting-started/). Procountor reviews the request, then provides the test company |
| **Demo data** | Partly: the chart of accounts and the VAT codes come preconfigured. Set up the company profile and a fiscal year before testing |

The test server is free and works like production, with a lower rate limit (see *Rate limits*). Procountor does not allow real or sensitive customer data on it ([general information](https://dev.procountor.com/general-information/)).

## Vendor fees

<CardGroup cols={2}>
  <Card title="Software editor (you)" icon="building">
    No fees. The partner program and the test server are free.
  </Card>

  <Card title="End user" icon="user">
    In Finland: €12.90 per month, plus €2.49 per month for each connected software, excl. VAT. In Sweden: the API is included in every plan.
  </Card>
</CardGroup>

In Finland, the fee is the same whatever the company's plan. There is no opening fee. In Sweden, there is no opening fee either.

In both countries, what is created through the API is priced as if it were created in Procountor, so vouchers count towards the plan's quotas ([general information](https://dev.procountor.com/general-information/)).

For plans and pricing, see Procountor's [Finnish price list](https://procountor.fi/wp-content/uploads/2025/11/Procountor_Taloushallinto_Hinnasto_01-01-2026.pdf) and its [Swedish API page](https://procountor.se/bokforingsprogram/tillaggstjanster/procountor-api/).

## Connect Procountor

<Card title="Procountor setup guide for end users" icon="book-open" href="/help/connectors/accounting/procountor" horizontal>
  The full step-by-step, with screenshots.
</Card>

**Before they start, your end users need:**

* an active Procountor account (Financials, Taloushallinto in Finnish)
* admin access to the company, to create a dedicated user with at least accounting write rights
* one connection per Procountor company: several companies means several connections

**To connect, they:**

* create the dedicated user in Procountor
* in Procountor, go to **Basics** › **API client keys**, click **New API key**, and enter the **Client ID** shown on the connection form
* paste the generated key into the **API key** field of the connection form

There is no consent screen: the connection is active as soon as the form is submitted. If you set **Environment** to **Sandbox**, they create the key in Procountor's test environment.

## Rate limits

Procountor applies a fixed quota per API client: 60 requests per second in production, and 90 requests per minute on the test server. The budget is shared by all connections that use the same Client ID.

Exceeding the limit may lead Procountor to suspend the service for the API client. Procountor says the limit may change, and does not document a way to raise it.

Chift automatically manages these limits to optimize performance and prevent interruptions. However, once the API rate limit is reached, Chift cannot bypass these limitations.

See Procountor's [API request documentation](https://dev.procountor.com/api-requests/).

## Limitations & specificities

<AccordionGroup>
  <Accordion title="Multi-folder">
    **One company per connection**: a Procountor API key gives access to a single company. The connector always returns one folder.
  </Accordion>

  <Accordion title="Chart of accounts & VAT">
    **Account type**: Procountor has no account type field. The connector infers it from the account number, using the Finnish or Swedish standard ranges for the company's country. An account outside the standard ranges may get the wrong type.

    **VAT codes**: Procountor has no single VAT code. A VAT treatment combines a rate, a type (sales or purchase) and a VAT status. The connector builds one code from the three, for example `25.5-SALES-1`. Use the codes returned by the VAT codes endpoint.
  </Accordion>

  <Accordion title="Journal entries">
    **One journal type**: every entry created through the API is a generic `JOURNAL` receipt. You cannot choose another journal.

    **Reverse charge**: with a reverse-charge VAT code, send a reversed VAT account. With any other code, do not send one. Otherwise, the entry is rejected.

    **VAT amount**: the VAT amount of a line must equal its amount multiplied by the code's rate, rounded to the cent, or the entry is rejected.

    **Clients and suppliers**: a line on a client or supplier is booked on that partner's default receivable or payable account in Procountor. If the partner has none, the entry is rejected. Set it in Procountor, or send the general account on the line.

    **Drafts**: an entry not sent as posted stays a draft in Procountor. If its attachment or its approval fails, the draft is invalidated.

    **Employee lines**: lines on an employee account are not supported.

    **Foreign currency**: an entry in another currency than the company's needs an exchange rate.
  </Accordion>

  <Accordion title="Numbering">
    **Entry number**: Procountor has no dedicated field for it. The number goes into the receipt's free-text name, which has no uniqueness check, so duplicates are not caught.
  </Accordion>

  <Accordion title="Attachments">
    **PDF size**: a PDF attached to an entry is limited to 10 MB.
  </Accordion>
</AccordionGroup>

## Coverage

<CoverageIframe api="accounting" connectors="Procountor" />
