Automation Hub Access documentation

Send resource data to Klappir

For customers and partners: SFTP for CSV files, or GraphQL when you prefer an API.

SFTP uploads are processed within 24 hours of file upload. Not sure which to pick? Email service@klappir.com klappir.com Privacy & Terms
Home
Path A:SFTP File Upload
Klappir Developer Docs SFTP File Upload

SFTP File Upload

The no-code path into Klappir. Drop a UTF-8 CSV onto your SFTP folder — Klappir processes uploaded files within 24 hours of file upload — no integration code, no engineering required. Access is SSH key only: you send Klappir your public key, we provision the folder, you connect with your private key.

Choose Your role in the sidebar to show customer or partner guidance. The links below jump to documentation sections.

Explore the guide

Shortcuts to topics in the left navigation — Getting started, templates, validation, and more.

Getting started

SSH key setup, connection test, and your first CSV upload.

CSV format basics

Encoding, separators, headers, and the conventions every template shares.

Edit / update / delete

Re-upload by Unique ID; zero quantity removes a row.

View and validate

24-hour processing SLA and how to confirm ingestion.

Running in production

Scheduling exports, handling failures, and monitoring uploads.

Getting started #

Once Klappir has installed your SSH public key, you can usually connect and upload within about one business day.

Your path as a Klappir customer
  1. 1
    Create an SSH key pair
    Generate a public/private key pair on your workstation before you contact Klappir. Step-by-step instructions are in Get your credentials. Keep the private key secret — you will only send Klappir the .pub file.
  2. 2
    Email service@klappir.com and request SFTP access.
    Include your company registration number, the SSH public key Klappir should install (paste the full single-line .pub contents), and the notification email address where import status messages should be sent. Never send your private key.
  3. 3
    Connect to your SFTP folder
    Klappir replies with your hostname, username, and path. Access is SSH key only (no password). Configure your SFTP client with the private key that matches the public key you submitted — see Get your credentials.
  4. 4
    Choose classification keys
    Each row needs at least one classification key — look them up in the Classification Browser (see Classifications).
  5. 5
    Pick and fill the right template
    Seven CSV templates cover fuel, upstream transportation & distribution, waste, three flavours of business travel, and goods & services. Download the Excel file from the template page you need, fill your rows, and save as UTF-8 CSV.
  6. 6
    Upload to your top-level folder
    Put the finished file in the home directory Klappir assigns you (not a subfolder unless Klappir told you otherwise). Klappir processes each file within 24 hours of upload.
Your path as a data partner
  1. 1
    Create an SSH key pair
    Generate a public/private key pair on your workstation before you contact Klappir. Step-by-step instructions are in Get your credentials. Keep the private key secret — you will only send Klappir the .pub file.
  2. 2
    Request partner SFTP access
    Email service@klappir.com with your organisation details, the SSH public key to install (same .pub rules as for customers), and the notification email address for import status messages. Klappir provisions one folder per downstream customer, keyed by their registration number; one login reaches all folders you are authorised for.
  3. 3
    Use the standard templates
    Same seven templates as customers. Every row must carry the correct Legal Entity (UUID) for the customer that row belongs to.
  4. 4
    Upload into each customer's directory
    Save UTF-8 CSVs and place them in the folder Klappir assigns for that customer under your partner root. Exact paths are confirmed when each customer is onboarded.
Connection details are issued per customer

Hostnames and example usernames in this guide are placeholders. The real values for your account are sent to you by email when access is provisioned.

CSV format basics #

All seven templates share the same conventions. Get these right once and they apply everywhere.

ConventionDetail
File formatComma-separated CSV (.csv). Excel files (.xlsx) are accepted but CSV is preferred — saves a conversion step.
EncodingUTF-8. Critical for non-ASCII characters in addresses, labels, and references (e.g. Icelandic names like Reykjavík).
SeparatorComma (,). Use double quotes around values that contain commas, e.g. "Borgartún 21, 105 Reykjavík".
Header rowFirst row must be the column headers exactly as shown in the template. Don't translate them or change the order.
Required fieldsColumns marked with * in the template header are required. Klappir rejects rows missing required values.
DatesISO 8601 (YYYY-MM-DD) preferred. Excel-style dates (DD/MM/YYYY) are accepted and auto-detected by locale.
DecimalsUse . as the decimal separator (123.45), not comma.
Country codesISO 3166-1 alpha-2, e.g. IS for Iceland, DK for Denmark.
FilenameUse a descriptive name including the date range, e.g. fuel_2024-03.csv. Filenames don't affect routing — Klappir picks the template based on the columns.

Fields you'll see on every template

A handful of columns appear across all seven templates. Understanding them once saves repeating the explanation.

ColumnWhat it means
Unique ID*Your own reference for this row. Used for deduplication — re-uploading a row with the same Unique ID updates the record rather than duplicating it. To delete a row, re-upload it with the same Unique ID and set the quantity (Value) to 0 — see Edit / update / delete. Pick a stable scheme like YOURCO-FUEL-2024-03-001 (YOURCO = your prefix) and stick with it.
Legal Entity (UUID)*The Klappir customer ID this row belongs to. For customers, use your organisation's UUID from the Klappir Platform: Settings → System → Entity IDs (same value as API customerId).For partners, this is the UUID of whichever downstream customer this row applies to. Each row can target a different customer.
Supplier Label*Name of the supplier or vendor in your records (e.g. "Summit Fuel Supply"). Used for traceability in Klappir reports.
Classification (UNSPSC)*Classification key for the activity — look it up in the Classification Browser (see Classifications). Column name reflects the template; the value must be a key Klappir supports.
Asset Label*The site, vehicle, or asset the activity is associated with — e.g. "Truck #14", "Main Office Building", "Wood Piling Road 312".
ReferenceOptional free-text reference such as an invoice number. Helps reconcile back to source documents.
Classifications

Every template needs at least one classification key per row. Look up keys in the Classification Browser — see Classifications for how many you need per template.

Classifications #

Klappir classifies each activity row so emissions use the right factors. The taxonomy is based on UNSPSC, with additional Klappir keys where the standard alone is not enough. Each CSV row needs a classification key Klappir recognises.

How many keys per row?

TemplatesClassification column(s)Count
Fuel, upstream transportation & distribution, business travel (all types), goods & servicesOne classification column — use the header from the template you downloaded (e.g. Fuel: Classification (UNSPSC); Goods & Services: Classification Key (UNSPSC))1 per row
WasteTwo columns: waste type and treatment (see Waste template for exact headers)2 per row — what the waste is, and how it was treated
Two keys on waste rows

Waste is the only template that needs two classification keys. The same material can have very different emissions depending on treatment (recycling vs landfill vs incineration). See the Waste template for column details.

CSV column headers often include (UNSPSC) because templates were designed around that standard. The value you enter must be a Klappir classification key from the browser below — not a raw UNSPSC code from elsewhere.

Where keys come from

Look up valid keys in the Klappir Classification Browser. It lists every key Klappir accepts for each data type — mostly UNSPSC-based, plus Klappir-specific keys the public UNSPSC catalogue does not include. Copy the key into your CSV classification column exactly as shown (hyphenated form, e.g. 15-10-15-05-K001 for diesel).

Many teams maintain a short internal spreadsheet that maps finance or ERP categories to keys from the browser, so every export row gets the right value without a manual lookup each time.

Building an integration via the GraphQL API? The same keys are returned by getClassifications — use the browser for exploration and the query when you need a machine-readable catalogue.

Practical rules

  • Match the activity — use a fuel key on fuel rows, a travel-related key on travel templates, and so on. A key from the wrong category is a common rejection reason.
  • Do not invent keys — if Klappir does not recognise a value, the row will fail validation (see Common errors).
  • Stay consistent — once you pick a key for a recurring activity (e.g. diesel for your fleet), reuse it unless the activity type genuinely changes.
Klappir Knowledge Base

Background on how UNSPSC and Klappir’s hierarchy drive emission factors — fallbacks and why granularity matters: How the Klappir Platform uses UNSPSC.

1Connect Get your credentials #

Klappir provisions SFTP access on request. Email service@klappir.com with your company registration number, the SSH public key you want installed on the server, and the notification email address where Klappir should send import status messages. Klappir does not use passwords for SFTP — only key-based login. You should get connection details back within about one business day.

SSH keys — what to send Klappir

You keep a key pair: a private key (secret, stays on your machine) and a public key (safe to share). Klappir installs the public key on the SFTP server; you authenticate with the private key in your SFTP client.

  1. If you don't already have a key, generate one on your workstation, for example: ssh-keygen -t ed25519 -f ~/.ssh/<your_username> (press Enter to skip a passphrase if your policy allows, or set one and enter it each time in the client).
  2. Open the public file — same folder as in step 1, with .pub added to the filename (e.g. ~/.ssh/<your_username>.pub). It is a single line starting with ssh-ed25519 or ssh-rsa.
  3. Paste that full line into your email to Klappir, or attach only the .pub file. Never send the private key file (no .pem without .pub, no id_ed25519 without .pub).
  4. Use the matching private key in your SFTP client when connecting (see Connect with your SFTP client below).

Connection details

Hostsftp.automationhub.klappir.io
Port22
ProtocolSFTP (SSH File Transfer Protocol)
AuthSSH public key only (no password)
Usernameyour-registration-number
Home directory/{your-registration-number}/
Before you connect

Host is always sftp.automationhub.klappir.io. Your username and home path are assigned when SFTP is provisioned — wait until Klappir confirms your public key is installed before connecting.

Connect with your SFTP client

Once Klappir has confirmed access, configure any SFTP client using the connection details above (replace placeholders with the values Klappir sent you).

  • Protocol — SFTP (SSH File Transfer Protocol). Not FTP or FTPES.
  • Host and portsftp.automationhub.klappir.io on port 22, unless Klappir gave you different values.
  • Username — your registration number (or the username in Klappir’s email).
  • Authentication — SSH public key / key file. Select your private key (never the .pub file you emailed to Klappir).
  • After connect — you should land in /{your-registration-number}/. Upload production CSVs to the top level of that folder unless Klappir told you otherwise. Use {your-registration-number}/test/ for dry-run files — see Email notifications.

Example: FileZilla

If you use FileZilla, map the fields like this (other clients use the same values with different labels):

FileZilla → Site Manager → New Site

  Protocol:   SFTP - SSH File Transfer Protocol
  Host:       sftp.automationhub.klappir.io
  Port:       22
  Logon type: Key file
  User:       5501234567
  Key file:   <path to your PRIVATE key, e.g. klappir_sftp>

Connect, then drag and drop CSV files into your home folder.
Optional: test from the terminal
# Private key path only (-i must not be the .pub file)
sftp -i ~/.ssh/klappir_sftp 5501234567@sftp.automationhub.klappir.io
sftp> pwd
# Expect: /5501234567 — then upload CSVs with put, or use your GUI client instead

2Templates Fuel #

Liquid and gaseous fuel — diesel, petrol, LPG, marine gas oil, natural gas, biofuels. Use this for fuel consumed by vehicles, generators, boilers, or any combustion equipment. Each row’s Value uses one supported unit: L (litres), kg, (m3), or kWh (kwh in the CSV unit column).

Download: Fuel template (.xlsx)

Columns

ColumnRequiredDescription
Unique IDrequiredYour reference for this row, used for deduplication. E.g. YOURCO-FUEL-2024-03-001
Legal Entity (UUID)requiredUUID of the Klappir customer this row belongs to.
Supplier LabelrequiredName of the fuel supplier (e.g. "Summit Fuel Supply").
DaterequiredWhen the fuel was delivered or consumed. ISO 8601 (2024-03-01) preferred.
ValuerequiredQuantity of fuel as a decimal number, e.g. 450.5
Unit (l/kg/m3/kwh)requiredUnit of the value. One of: l (litres, L), kg, m3 (cubic metres), kwh (kilowatt-hours, kWh).
Fuel descriptionrequiredFree-text description, e.g. "Diesel B7", "Marine Gas Oil"
Customer AccountoptionalYour customer account number with the supplier, if relevant.
Delivery MethodoptionalHow the fuel was delivered, e.g. "Tank truck", "Forecourt"
Address (country)requiredISO country code where fuel was delivered, e.g. IS.
Classification (UNSPSC)requiredClassification key for the fuel type — Classification Browser.
Asset LabelrequiredThe vehicle, site, or asset that consumed the fuel.
ReferenceoptionalFree-text reference, e.g. invoice number.

Sample rows (example)

Unique ID* Legal Entity (UUID)* Supplier Label* Date* Value* Unit* Fuel description* Address* Classification* Asset Label* Reference
YOURCO-FUEL-2024-03-001afaf2111-f5cc-...28b5dSummit Fuel Supply2024-03-01450.5lDiesel B7IS15-10-15-05-K001Truck #14Invoice 4521
YOURCO-FUEL-2024-03-002afaf2111-f5cc-...28b5dSummit Fuel Supply2024-03-02312.0lDiesel B7IS15-10-15-05-K001Truck #08Invoice 4522
YOURCO-FUEL-2024-03-003afaf2111-f5cc-...28b5dHarbour Energy Co.2024-03-03189.7lDiesel B7IS15-10-15-05-K001Truck #14Invoice 8841

2Templates Upstream transportation & distribution #

Upstream transportation & distribution — inbound, outbound, and internal logistics. Used by logistics providers, shipping companies, and manufacturers tracking Scope 3 supply chain emissions. Captures origin and destination countries, distance in kilometres, weight in kg, and whether the move is inbound, outbound, or internal from the customer’s perspective.

Download: Upstream transportation & distribution template (.xlsx)

Columns

ColumnRequiredDescription
Unique IDrequiredYour row reference.
Legal Entity (UUID)requiredKlappir customer UUID.
Supplier LabelrequiredCarrier or freight forwarder name.
Date (of shipment)requiredWhen the shipment occurred.
Load Address (country code)requiredISO country code of pickup point.
Unload Address (country code)requiredISO country code of destination.
Shipping distance (km)requiredDistance travelled, in kilometres.
Weight (kg)requiredMass in kilograms for this upstream transportation & distribution record.
Transport Type (inbound/outbound/internal)requiredinbound, outbound, or internal from the customer’s perspective (internal = moves within the organisation’s own sites).
Data LabelrequiredDescription or label for this shipment.
Asset LabelrequiredSite or vehicle reference.
Classification (UNSPSC)requiredClassification key for the upstream transportation & distribution category.
ReferenceoptionalBill of lading or invoice reference.

Sample rows (example)

Unique ID* Legal Entity (UUID)* Supplier Label* Date* Load country* Unload country* Distance (km)* Weight (kg)* Transport type* Data Label* Asset Label* Classification* Reference
YOURCO-UTD-2024-03-088afaf2111-f5cc-...28b5dNorthwind Line2024-03-08ISIS5218500outboundB/L ICE-2024-7781Trailer T-40278101802U002U001INV 99204

2Templates Waste #

Waste collected from the customer's operations. Used by waste haulers and environmental service companies, and by direct customers reporting their own waste streams. Records weight, pickup location, plus separate classification keys for the type of waste and the treatment method (recycling, landfill, incineration, etc.).

Download: Waste template (.xlsx)

Columns

ColumnRequiredDescription
Unique IDrequiredYour row reference.
Legal Entity (UUID)requiredKlappir customer UUID.
Supplier LabelrequiredWaste hauler or treatment provider name.
DaterequiredPickup date.
ValuerequiredQuantity of waste as a decimal.
Unit (kg)requiredUse kg (mass in kilograms).
Product LabelrequiredFree-text waste description, e.g. "Mixed commercial waste".
Pickup address (country)requiredISO country code of pickup site.
Pickup locationoptionalSpecific street address or site label.
Waste type classification (UNSPSC)requiredClassification key for the type of waste.
Waste treatment classification (UNSPSC)requiredClassification key for the treatment method (recycling, landfill, incineration, composting, etc.).
Asset LabelrequiredSite reference.
ReferenceoptionalPickup ticket or invoice reference.
Two classification keys per row

Waste records carry two classification keys — one for what the waste is (e.g. mixed paper, food waste, hazardous chemicals) and one for how it's treated (recycled, landfilled, incinerated). Both drive the emissions calculation — the same waste type has very different emissions depending on treatment. Look up both keys in the Classification Browser.

Sample rows (example)

Unique ID* Legal Entity (UUID)* Supplier Label* Date* Value* Unit* Product Label* Pickup country* Pickup location Waste type* Treatment* Asset Label* Reference
YOURCO-WASTE-202403-001afaf2111-f5cc-...28b5dIceland Waste Solutions2024-03-051200kgMixed municipal — Reykjavík depotISGate B — Sundagarðar111416K017612K02K03Reykjavík depotTK-88420

2Templates Business Travel — Flight #

Air travel for business purposes. Used by travel agencies, corporate travel management companies, and organisations self-reporting employee flights. Origin and destination airports use IATA three-letter codes (e.g. KEF, CPH, JFK).

Download: Business Travel — Flight template (.xlsx)

Columns

ColumnRequiredDescription
Unique IDrequiredYour row reference.
Legal Entity (UUID)requiredKlappir customer UUID.
Supplier LabelrequiredAirline or travel agency name.
Date (of travel)requiredDate of the flight.
From Airport (IATA code)requiredOrigin airport, IATA code (e.g. KEF).
To Airport (IATA code)requiredDestination airport, IATA code.
Passengers (count)requiredNumber of passengers on the booking.
Travel DescriptionrequiredFree-text description, e.g. "Annual conference attendance".
Classification (UNSPSC)requiredClassification key reflecting cabin class.
Asset LabelrequiredDepartment, project, or cost-centre label.
ReferenceoptionalPNR or booking reference.

Sample rows (example)

Unique ID* Legal Entity (UUID)* Supplier Label* Date* From* To* Passengers* Travel Description* Classification* Asset Label* Reference
YOURCO-FLT-2024-03-014afaf2111-f5cc-...28b5dIcelandair2024-03-12KEFCPH1Client meeting — Copenhagen78111502U003U001Sales team / EMEAPNR ABC123

2Templates Business Travel — Surface #

Non-aerial business travel — road, rail, ferry, and sea. Use for taxis, rental cars, employee mileage, trains, ferries, and any combination thereof. Captures origin and destination countries plus distance in kilometres.

Download: Business Travel — Surface template (.xlsx)

Columns

ColumnRequiredDescription
Unique IDrequiredYour row reference.
Legal Entity (UUID)requiredKlappir customer UUID.
Supplier LabelrequiredTaxi company, car rental, rail operator, ferry company, or Employee for mileage claims.
Date (of travel)requiredDate of the journey.
From Country (country code)requiredISO country code of origin.
To Country (country code)requiredISO country code of destination.
Distance (km)requiredTotal distance, kilometres.
Passenger countrequiredNumber of passengers.
Travel DescriptionrequiredFree-text description.
Classification (UNSPSC)requiredClassification key for transport mode.
Asset LabelrequiredDepartment or cost-centre.
ReferenceoptionalBooking or expense reference.

Sample rows (example)

Unique ID* Legal Entity (UUID)* Supplier Label* Date* From country* To country* Distance (km)* Passengers* Travel Description* Classification* Asset Label* Reference
YOURCO-SURF-2024-03-021afaf2111-f5cc-...28b5dHerjólfur2024-03-15ISIS142Ferry — staff site visit78111706Field operations / SouthTicket H-44102

2Templates Business Travel — Hotel #

Hotel stays for business purposes. Used by travel agencies and organisations tracking Scope 3 business travel. Country drives the emission factor (hotels in different countries have very different per-night carbon footprints depending on the local energy grid).

Download: Business Travel — Hotel stays template (.xlsx)

Columns

ColumnRequiredDescription
Unique IDrequiredYour row reference.
Legal Entity (UUID)requiredKlappir customer UUID.
Check in daterequiredDate of check-in.
CountryrequiredISO country code where the hotel is located.
Number of nightsrequiredTotal nights stayed.
Number of roomsrequiredRooms booked.
Number of guestsrequiredNumber of guests across all rooms.
Stay descriptionrequiredFree-text description, e.g. hotel name.
Classification (UNSPSC)requiredClassification key for accommodation type.
Asset LabelrequiredDepartment or cost-centre.
ReferenceoptionalBooking reference.
Note: Supplier Label not used here

Unlike most templates, the hotel template does not have a separate Supplier Label column — put the hotel name in Stay description instead.

Sample rows (example)

Unique ID* Legal Entity (UUID)* Check in date* Country* Nights* Rooms* Guests* Stay description* Classification* Asset Label* Reference
YOURCO-HOTEL-2024-03-009afaf2111-f5cc-...28b5d2024-03-18DK211Tivoli Hotel — client workshop90111801Sales team / EMEAConf. DK-88331

2Templates Goods & Services #

Purchased goods and services — Scope 3 Category 1 reporting. Each row represents a procurement record. The most flexible template: you can supply quantity (kg) plus a known emission factor (kgco2e), or you can supply just the quantity and let Klappir apply a default emission factor based on the classification key.

Download: Goods & services template (.xlsx)

Columns

ColumnRequiredDescription
Unique IDrequiredYour row reference.
Legal Entity (UUID)requiredKlappir customer UUID.
Supplier LabelrequiredVendor name.
DaterequiredPurchase date.
Unit (kg)required (one of)Unit of the value, currently kg.
Valuerequired (one of)Quantity purchased.
kgco2erequired (one of)Direct CO₂e emissions for this purchase, if you have a verified figure from the supplier.
kgco2e Source (if applicable)optionalReference for the kgco2e value (EPD, supplier statement, etc.) when supplied.
Product LabelrequiredFree-text product name, e.g. "Wooden piling".
Classification Key (UNSPSC)requiredClassification key for the product or service category.
Asset LabelrequiredSite or project the purchase is associated with.
ReferenceoptionalPO or invoice number.
Quantity-based or emission-based — supply at least one

Marked with ** in the original template, you must supply either quantity (Unit + Value) or a direct emission figure (kgco2e). If you supply both, Klappir uses your kgco2e value as authoritative and stores the quantity for traceability.

Sample rows (example)

Unique ID* Legal Entity (UUID)* Supplier Label* Date* Unit* Value* kgco2e* Product Label* Classification* Asset Label*
67ef84af80a823163150-3244-...80a8ACME Suppliers Inc2026-01-15kg420.0Wooden piling30102804Wood Piling Road 312
162843c10333acde070d-8c4c-...0333ACME Suppliers Inc2026-02-07kg12.0Apples503015Main Office Building

3After upload Edit, update & delete data #

SFTP is your correction channel. You do not edit rows in place on the server — you change the CSV and upload again. Klappir matches each row by Unique ID (the same identifier as externalId in the GraphQL API). Understanding updates and deletions upfront saves painful rework later.

Processing time (SLA)

Klappir processes uploaded files within 24 hours of file upload. After that window, accepted rows appear in the Klappir platform for the organisation and period you expect. Import status emails (see Email notifications) usually arrive sooner — use them together with platform spot-checks (see View and validate data) after each upload, not only on the first run.

Update an existing row

To change a record that already ingested successfully:

  1. Keep the same Unique ID as the original row.
  2. Change any other columns that need correcting (date, quantity, classification, supplier, and so on).
  3. Upload a CSV that includes the corrected row — it can be the full export again or a small file with only the changed rows, as long as headers match the template.

Klappir treats the new file as an update for that Unique ID, not a second copy. This is the same deduplication behaviour described in CSV format basics.

GraphQL equivalent

Re-submit a mutation record with the same externalId to update it, or set quantity fields to zero to delete. See Edit / update / delete in the GraphQL docs.

Delete a row

To remove a record from Klappir, upload a row with the same Unique ID and set the quantity column to zero:

  • Fuel, upstream transportation & distribution, waste, goods & services — set Value to 0.
  • Business travel templates — set the primary quantity field to 0 (for example distance, nights, or passenger count as defined in that template).

Do not delete the row from your CSV and expect Klappir to infer removal — absence from a new file does not delete prior data. The zero-quantity row is the deletion signal.

Recommended correction workflow

StepAction
1Confirm the original row ingested — View and validate data.
2Fix the source export or build a minimal correction CSV with the same template headers.
3Re-upload; wait up to 24 hours for processing.
4Validate again in the platform. If the row still looks wrong, check Common errors or contact service@klappir.com.

Example: to fix YOURCO-FUEL-2024-03-002 after a wrong date, change the cell, re-upload a one-row CSV with the same Fuel headers, and confirm in the platform after processing (up to 24 hours).

3After upload View and validate data #

Uploading is only half the job. Use the Klappir platform to confirm that rows were accepted and appear under the right legal entity and time range. Pair that with the error patterns in this guide when something does not show up as expected.

When to check

Allow up to 24 hours after file upload for Klappir to process the file. If nothing changes after that, treat it as an ingestion or validation issue rather than normal delay.

What emails to expect after upload

Klappir emails the notification address provisioned for your SFTP account. You typically receive two messages per import:

  1. Processing started — after the file passes full-file validation and an import run is created, when rows are accepted for processing but before row messages are sent to the queue (subject: Klappir SFTP import: processing started). Includes import run id, file name, dry-run yes/no, and how many rows were accepted. A later queue or ingestion failure can still produce a failed final email.
  2. Final outcome — after every enqueued row has been recorded: success, partial success, failed, or (for test uploads that pass file-level validation) dry-run email. File-level problems that stop before enqueue may send only a failed email with no “processing started” message.

Full subjects, routing rules, and how to read partial-success or failure details: Email notifications.

What to verify in the Klappir platform

  • Organisation — activity is attributed to the legal entity matching Legal Entity (UUID) in the CSV (for customers, your own UUID; for partners, each downstream customer).
  • Time period — dates on rows map to the reporting period you expect (monthly uploads should appear in that month).
  • Volume — row counts and totals are in the right ballpark compared to your source system (fuel litres, waste kg, travel segments, and so on).
  • Classification — categories line up with the classification keys you submitted; unexpected gaps often mean rejected rows.

Interpreting validation outcomes

What you seeLikely meaningWhat to do
Data appears as expected within 24 hoursFile and rows acceptedNo action — continue your regular export schedule.
Partial data — some periods or sites missingSome rows ingested; others failed during row processing after the file was acceptedCheck for a partial success email with failed Unique IDs; fix the listed row/API issues and re-upload. See Email notifications.
Nothing new after 24 hoursFile-level rejection, wrong folder, or transfer never completedCheck for a failed import email, SFTP client logs, filename, and template headers. Re-upload after fixing.
Duplicates or doubled totalsChanged Unique ID scheme or re-sent overlapping exportsStabilise IDs; use Edit / update / delete to correct instead of inventing new IDs for the same activity.
Garbled characters in labelsEncoding issueRe-save as UTF-8 CSV and upload again.
Row-level vs file-level failures

File-level problems (wrong headers, empty file, corrupt encoding, row parse errors, unknown classification keys, and similar issues caught before enqueue) reject the entire upload — you typically get a failed email without “processing started”. Partial success means the file was accepted and rows were queued; some rows then failed during ingestion (for example API or mutation errors on specific Unique IDs). The Common errors section lists common file-level causes.

3After upload Email notifications #

After you upload a CSV, Klappir sends automated status emails to the notification address stored for your SFTP username. Use them as an early signal before you spot-check data in the platform (View and validate data).

Who receives email

RuleDetail
RecipientThe notification email address on file for the SFTP username on the uploaded file.
ProvisioningProvide this address when you request SFTP access — see Get your credentials. Klappir stores it during setup.
SenderFrom a Klappir system address — you do not configure the sender.
No emailIf the uploaded file cannot be matched to an SFTP account, or no active customer record exists — the send is skipped on Klappir’s side.
No duplicatesEach import receives at most one final outcome email — the same run is not finalised twice.

Typical timeline

For a normal production upload to your home folder:

  1. Processing started — after full-file validation, when Klappir registers a new import job and rows are accepted for processing (before row messages are queued). Sent only for a new import, not retries of the same open run. Does not guarantee every row will succeed — a later queue or ingestion failure can still end in failed.
  2. Final outcome — after enqueued rows have been processed: success, partial success, failed, or (for valid test uploads) dry-run summary (see below).

If the file fails before rows are accepted for processing (file-level failure), you may receive only a failed email with a file-level summary — no “processing started” message.

Email types

SubjectWhenWhat it tells you
Klappir SFTP import: processing startedFile passed validation; import registered; rows accepted for processing (before queue send)Import reference id, file name, dry-run yes/no, rows accepted, and that a final email will follow. Row queue or ingestion can still fail afterwards.
Klappir SFTP import: failedFile-level failure before rows are accepted for processing (includes row validation and unknown classification keys caught in Transform)Import reference id, file name, dry-run flag, and file-level error (empty file, bad headers, missing Legal Entity (UUID) / Unique ID, mixed data types, unknown classifications, etc.).
Klappir SFTP import: successEvery enqueued row succeededTotal, successful, and failed row counts — “no action needed”.
Klappir SFTP import: partial successFile accepted and rows queued; some rows failed during ingestionRow counts, up to 25 post-enqueue errors by Unique ID (for example API or mutation failures), and instructions to fix failed rows and re-upload. Not used for CSV validation problems caught before enqueue.
Klappir SFTP import: failedFile was accepted but every enqueued row failed during ingestionRow counts, per-row error details, and instructions to correct and re-upload.
Klappir SFTP import: dry-run emailFile under {username}/test/*.csv passed file-level validation and finished recording row outcomesDry-run completed, row counts, errors if any — rows were validated but not written to live data in Klappir.

How this ties to platform checks

  • Success email — still spot-check volumes and periods in the platform within 24 hours; email confirms ingestion completed cleanly.
  • Partial success — the file was accepted; some rows failed during ingestion. Fix the Unique IDs and issues listed in the email, then re-upload; see Edit / update / delete.
  • File-level failed — entire file rejected; match symptoms in Common errors, fix the CSV, upload again.
  • No email at all — confirm transfer completed, correct folder, and that Klappir has a notification email on file for your account. Wrong file path or missing account metadata can suppress mail.

3After upload Common errors #

Most rejection reasons fall into a small handful of categories. Once you've seen each once, you'll fix them in seconds. When the pipeline rejects rows or a whole file, the reason is usually tied to one of the patterns below — match your symptom, apply the fix, and re-upload.

The frequent flyers

ErrorCauseFix
Header row not recognisedColumn names don't match any template, often because of an extra space or different capitalisation.Re-download the official template from the matching template page and copy your data into it. Don't modify the header row.
Required field missingA column marked * is blank.Either fill the cell or delete the row entirely.
Invalid country codeSpelled out ("Iceland") or three-letter ("ISL") instead of ISO alpha-2 ("IS").Use ISO 3166-1 alpha-2: 2-letter codes only. IS, DK, NO, US.
Date couldn't be parsedMixed format (03/01/24), Excel serial number, or an impossible date like 2024-13-05.Use ISO 8601: 2024-03-01. If you must use a national format, be consistent across the whole file.
Decimal separatorEuropean comma decimals (123,45) instead of period (123.45).Configure your CSV export to use period as the decimal separator. In Excel, this is the regional setting.
Unknown classification keyThe key is not in Klappir’s current taxonomy for this data type (misspelled, retired, or wrong template).Look up a current key in the Classification Browser and copy it exactly. Your account manager can help during onboarding.
UUID doesn't match an authorised customerThe Legal Entity (UUID) column contains an ID that isn't yours, or — for partners — a customer that hasn't authorised your integration.For customers: confirm you're using the UUID Klappir gave you during onboarding. For partners: the customer needs to enable your integration in their Klappir account first.
File encodingSpecial characters (Icelandic, Nordic, accented) appear garbled.Save as UTF-8. In Excel: File → Save As → CSV UTF-8 (Comma delimited). Avoid the plain "CSV" option which uses Windows-1252.
Comma inside a quoted valueAddress contains a comma but isn't quoted.Wrap any value containing a comma in double quotes: "Borgartún 21, 105 Reykjavík".
Unit not in allowed listUsed a unit not listed in the template, e.g. gallons in the Fuel template.Convert to one of the allowed units before upload. The Fuel template accepts l, kg, m3, or kwh only (L, kg, m³, kWh).

If a whole file is rejected

A small number of conditions cause Klappir to reject the entire file rather than process row by row:

  • The file isn't a recognised CSV (binary content, wrong extension, corrupted).
  • The header row doesn't match any of the seven templates.
  • The file is empty or has no data rows after the header.

In all of these cases Klappir rejects the file at ingest time with a clear file-level reason (or Klappir can confirm what happened). Fix and re-upload — there's nothing to clean up on Klappir's side. You should receive subject Klappir SFTP import: failed with the file-level summary if notification email is configured — see Email notifications.

Interpreting failed and partial-success emails

Terminal emails after row processing include counts and, when relevant, error lines keyed by your row’s Unique ID (same value as API externalId).

Email subjectMeaningWhat to do
… partial successFile was accepted and queued; some rows failed during ingestionOpen the email’s error list (up to 25 rows). For each Unique ID, fix the underlying row/API issue the email describes and re-upload — good rows are already in Klappir; only failed rows need correction. Pre-enqueue CSV problems produce file-level failed, not partial success.
… failed (after processing started)Every row failed during ingestionTreat as a full rework: compare the email’s row/API errors to your CSV, fix all listed issues, re-upload the file (or a corrected subset with stable Unique IDs).
… failed (no processing started)File never reached the row queueFile-level problem — headers, empty file, classification lookup, mixed templates, etc. Fix the whole file; see The frequent flyers and If a whole file is rejected above.
… dry-run emailTest path under test/; file passed file-level validationNo live data was written. Use row errors in the email to fix the CSV, then upload to your production folder when ready. File-level validation failures on test/ still send failed.

Import run id in the email helps Klappir support if you contact service@klappir.com.

Running in production #

Once your first upload works end-to-end, the next step is making this part of your routine without having to think about it.

Schedule the export

Most customers run their CSV export on a fixed cadence — daily, weekly, or monthly. Use cron, Windows Task Scheduler, or your ERP's built-in scheduler to drop files onto the SFTP server automatically.

Pick a stable Unique ID scheme

Use a stable scheme such as YOURCO-FUEL-2024-03-001 — replace YOURCO with your own short prefix, then type, year-month, and a sequence number. Once you commit to a scheme, don't change it. Future you will thank you when reconciling historical data.

Monitor the notification mailbox

Watch the notification inbox Klappir configured when your SFTP access was set up. Treat partial success and failed subjects as operational alerts — fix listed Unique IDs and re-upload before your next scheduled export. See Email notifications.

Confirm data in Klappir

After each upload, allow up to 24 hours for processing, then spot-check in the Klappir platform that new activity appears as you expect for the right organisation and time period. A success email is helpful but not a substitute for platform checks — see View and validate data.

Keep SFTP client and scheduler logs

Your SFTP client or automation logs show whether a transfer completed. If a file never left your side, the issue is local (path, key, network) before it reaches Klappir.

Keep originals locally

Klappir archives processed files internally for traceability, but you should keep your own copies of every file you upload. They're your audit trail for the export, separate from Klappir's record of ingestion.

Refresh classification keys

The classification taxonomy expands over time. If you're hard-coding keys in your export, revisit them every 6–12 months in the Classification Browser or with your Klappir account manager.

When something goes wrong

Email service@klappir.com with the timestamp of the upload attempt, the filename, what you see in the Klappir platform (if anything), and any error text from your SFTP client or scheduler logs. The Klappir team can usually help within a business day.

Want to switch to GraphQL later?

If you grow into a use case that needs real-time submission, programmatic batching, or fine-grained error handling, the GraphQL API is the next step up. Same data, same classifications, same customer model — different transport.

Home
Path B:GraphQL API
Klappir Developer Docs GraphQL API

Klappir GraphQL API Reference

A single GraphQL endpoint for submitting data into the Klappir platform. The same data types and field concepts as the SFTP CSV templates — see SFTP and API field alignment.

Choose Your role in the sidebar to show customer or partner guidance. Section links in the left navigation open documentation pages.

API Endpoint & Authentication

Endpoint: https://api.klappir.com/graphql

Required headers on every request:

{
  "Content-Type": "application/json",
  "x-api-key": "your-api-key-here"
}

No API key yet? Email service@klappir.com to request one. If you'd rather avoid building an integration entirely, see the SFTP path.

Your path as aKlappir customer
  1. 1
    Get an API key from Klappir
    Email service@klappir.com to request a key. You pass it on every request as the x-api-key header (details in the Getting started section).
  2. 2
    Find your organisation UUID
    In the Klappir Platform, open Settings → System → Entity IDs — the value you can see is your customerId on every mutation.
  3. 3
    Look up classification keys
    Use the Classification Browser or call getClassifications for the activity types you'll be sending.
  4. 4
    Submit your activity records
    Use the create* mutation matching your data — fuel, waste, business travel, upstream transportation & distribution, goods and services.
  5. 5
    Correct or remove rows when needed
    Re-submit with the same externalId to update; set quantity fields to 0 to delete — see Edit / update / delete.
Your path as adata partner
  1. 1
    Get an API key from Klappir
    Email service@klappir.com to request a key. You pass it on every request as the x-api-key header (details in the Getting started section).
  2. 2
    Discover authorised customers
    Call getActiveCustomers to see which Klappir customers have enabled your integration. Each id in the response is the customerId for that customer's records. Refresh regularly.
  3. 3
    Look up classification keys
    Use the Classification Browser or call getClassifications for the activity types you'll be sending.
  4. 4
    Submit your activity records
    Use the create* mutation matching your data — fuel, waste, business travel, upstream transportation & distribution, goods and services. Each record carries a customerId, so one batch can cover many customers at once.
  5. 5
    Correct or remove rows when needed
    Re-submit with the same externalId to update; set quantity fields to 0 to delete — see Edit / update / delete.

Getting started #

The Klappir Public API is a single GraphQL endpoint. All requests use HTTP POST with Content-Type: application/json. There are two operation types:

query

Read data from Klappir — for example classification keys and other reference data you need before submitting records about your own organisation.Read data from Klappir — customers you're authorised to send data for, valid classifications, and related metadata.

mutation

Write data to Klappir — submit fuel, waste, travel, upstream transportation & distribution, and other sustainability records.

Every request body is a JSON object with two keys:

KeyRequiredDescription
queryrequiredA string containing the GraphQL operation.
variablesoptionalA JSON object with input parameters referenced inside the query string.

In GraphQL, ! marks a field as non-null (required). For example, CreateFuelInput! means the input argument must be provided.

The examples below walk through a first successful read for your audience. If a request fails before that works, jump to Troubleshooting common API errors at the end of this section.

Your first call

Your organisation's customerId comes from the Klappir Platform (Settings → System → Entity IDs). Before your first fuel mutation, fetch valid classification keys:

{
  "query": "query { getClassifications(input: { dataType: [FUEL] }) { key level dataType usage description } }"
}
{
  "data": {
    "getClassifications": [
      {
        "key": "15-10-15-05-K001",
        "level": 5,
        "dataType": "FUEL",
        "usage": "General classification",
        "description": "Diesel 100% mineral"
      },
      {
        "key": "15-10-15-06-K001",
        "level": 5,
        "dataType": "FUEL",
        "usage": "General classification",
        "description": "Petrol 100% mineral"
      }
    ]
  }
}

Pick a key from the response for classificationKey on each record. Full options and filters: getClassifications. Mutation examples use customerId: afaf2111-f5cc-4c69-b806-46d318e28b5d as a placeholder — replace it with your own UUID from the Platform.

Your first call

As a partner, your first read lists Klappir customers that have authorised your integration:

{
  "query": "query { getActiveCustomers { id, name, registration } }"
}
{
  "data": {
    "getActiveCustomers": [
      {
        "id": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
        "name": "Example Customer Ltd",
        "registration": "5501234567"
      }
    ]
  }
}

Each id is the customerId to set on records for that customer. Cache the list and refresh it on a schedule. Partner flows also use getClassifications before submitting.

Troubleshooting common API errors

If a request fails, use this table to diagnose quickly and apply the exact fix.

What you seeLikely causeExact fix
401 UnauthorizedMissing or invalid x-api-key header.Send both headers on every request: Content-Type: application/json and x-api-key: <your-key>. If it still fails, request a new or rotated key from service@klappir.com.
GraphQL validation error (for example: required field missing, wrong type)Payload does not match mutation input type (for example missing time, string passed where number is required).Check the mutation's input type and ensure every required field is present with correct type. Start from the doc's example payload, then add fields incrementally.
customerId missing / null / unauthorized-customer style errorRecord has no customerId, or ID is not currently authorised for your integration.Use the UUID from Platform Settings → System → Entity IDs (must match your organisation).Fetch getActiveCustomers, pick an id from that result, and set it on every record. Refresh this list regularly before submission.
Invalid or unknown classificationKeyClassification key is outdated, misspelled, or for the wrong data type.Look up a current key in the Classification Browser or via getClassifications. Do not hard-code old values; refresh your classification cache on a schedule.

Sending data, in concept #

Before diving into specific mutations, three fields appear on nearly every record.

In the GraphQL sections below, field tables include a Req column: required (green) means non-null in the schema or a mandatory nested input; optional (grey) means you may omit the field. Nullable quantity fields can still require at least one value per row — see each mutation’s note above its table.

ReqFieldTypeDescription
requiredcustomerIdString!Your organisation's UUID from the Klappir Platform: Settings → System → Entity IDs.The id from getActiveCustomers for the customer this row belongs to. Routes the record to the correct Klappir account.
requiredclassificationKeyString!Classification key from getClassifications (UNSPSC-based hierarchy with Klappir extensions). Determines how the record is categorised in emissions calculations.
requiredtimeDateTime!ISO 8601 timestamp for when the activity occurred. Always UTC.
optionalexternalIdStringYour own reference ID (required on each mutation input row). Same role as Unique ID on SFTP — re-submitting with the same externalId updates the record; zero quantity removes it. See Edit / update / delete.

Classifications, briefly

Klappir’s classification system is based on UNSPSC, with additional keys where needed. Each record needs a supported classification key — look them up in the Classification Browser, or call getClassifications without input for all keys your integration supports, or pass dataType: ["FUEL", …] (an array) to narrow.

externalId — your deduplication anchor

The externalId is your record's identity from your system's perspective — the API equivalent of SFTP Unique ID. Use a stable scheme like YOURCO-FUEL-2024-03-001 (YOURCO = your prefix; then type, year-month, sequence). Pick a scheme and stick with it. Corrections and deletions use the same rules as the SFTP path; see Edit / update / delete.

Cache key values from getClassifications (e.g. under dataType: ["FUEL"]) and refresh on a schedule — always prefer live lookups over hard-coded keys as the taxonomy grows.

Mutation quick reference

Seven create-style mutations, one per data category. Use the one that matches what you have:

MutationData typeKey quantity field(s)
createFuelFuel consumptionAny combination of liters (L), kg, m3, kwh per row
createCargoUpstream transportation & distributiontransportType, date, addresses, distance, weight
createWasteWaste disposalkg
createFlightTravelAir travelorigin, destination, cabin class, passengers
createSurfaceTravelRoad / rail / sea traveldistanceTraveled, addresses, passengers
createHotelTravelHotel staysnights, country
createGoodsServicesPurchased goods & servicesproductLabel, classificationKey, at least one of kg / kgco2e

SFTP and API field alignment #

The GraphQL API and SFTP CSV templates describe the same data. Data types, classification keys, customer routing, and deduplication rules align — only the transport differs (HTTP mutations vs file upload). If you know one path, you can map directly to the other.

Shared concepts

ConceptSFTP (CSV)GraphQL API
Customer routingLegal Entity (UUID)customerId
Row identity / deduplicationUnique IDexternalId
ClassificationOne classification column per template (header from official CSV); waste uses two columnsclassificationKey (and wasteClassificationKey / treatmentClassificationKey for waste)
Activity dateDate (ISO 8601)time (DateTime!, UTC)
Update existing rowRe-upload same Unique IDRe-submit same externalId
Delete rowSame Unique ID, quantity 0Same externalId, zero quantity fields
Processing SLA (batch)Within 24 hours of file uploadMutations are processed on request; responses are immediate

Data type ↔ mutation ↔ template

Data typeSFTP templateGraphQL mutation
FuelFuelcreateFuel
Upstream transportation & distributionUpstream transportation & distributioncreateCargo
WasteWastecreateWaste
Business travel — flightBusiness Travel — FlightcreateFlightTravel
Business travel — surfaceBusiness Travel — SurfacecreateSurfaceTravel
Business travel — hotelBusiness Travel — HotelcreateHotelTravel
Goods & servicesGoods & ServicescreateGoodsServices

Updates and deletions follow the same rules on both paths — see Edit / update / delete (API) and Edit / update / delete (SFTP). Both paths use the same Klappir classification keys — look them up in the Classification Browser or via getClassifications. See also SFTP: Classifications and the Knowledge Base article on UNSPSC and emission factors.

1Discover QUERY getActiveCustomers #

List Klappir customers your integration may send data for. This query returns every customer that has enabled your integration. Refresh regularly — authorisation can change overnight.

Authorisation first

The API only accepts data for customers who have explicitly granted your integration access. getActiveCustomers returns only currently authorised customers. If a customer isn't in the list, you can't send data for them yet.

QUERYGet active customersgetActiveCustomers

Returns [Customer!]! — no arguments required

Query

query getActiveCustomers {
  getActiveCustomers {
    id
    name
    registration
    description
    address { country address city postalCode }
  }
}

Response — example

{
  "data": {
    "getActiveCustomers": [
      {
        "id": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
        "name": "Example Customer Ltd",
        "registration": "5501234567",
        "description": null,
        "address": {
          "country": "IS",
          "address": "Borgartún 21",
          "city": "Reykjavík",
          "postalCode": "105"
        }
      }
    ]
  }
}

1Discover QUERY getClassifications #

Fetch valid classification keys for tagging your data records. Every record you submit needs a classificationKey. For browsing and copy-paste, use the Classification Browser. This query returns the same keys programmatically — mostly UNSPSC-based, plus Klappir extensions.

QUERYClassificationsgetClassifications

Returns [Classification!]!

Arguments

ReqArgumentTypeDescription
optionalinputGetClassificationsInputOptional. Filter by dataType — an array of DataTypeEnum values (e.g. [FUEL]) — and/or keyPrefix string. Omit input to return classifications for all data types your integration supports.

Query

query getClassifications($input: GetClassificationsInput) {
  getClassifications(input: $input) {
    key
    level
    dataType
    usage
    description
  }
}

Response fields (Classification)

ReqFieldTypeDescription
requiredkeyID!Klappir classification key — copy verbatim into classificationKey (or waste keys) on mutations. Hyphen-separated hierarchy (e.g. 15-10-15-05-K001), not raw compact UNSPSC commodity codes.
requiredlevelInt!Depth in the classification hierarchy (higher = more specific).
requireddataTypeDataTypeEnum!Which mutation family this key applies to (e.g. FUEL, WASTE).
requiredusageString!How Klappir expects the key to be used (internal label).
requireddescriptionString!Human-readable label for integrators.

Variables — filter by fuel

{ "input": { "dataType": ["FUEL"] } }

dataType is a list in the schema — use an array even for one type, e.g. ["FUEL", "WASTE"] to prefetch keys for multiple templates.

Response

{
  "data": {
    "getClassifications": [
      {
        "key": "15-10-15-05-K001",
        "level": 5,
        "dataType": "FUEL",
        "usage": "General classification",
        "description": "Diesel 100% mineral"
      },
      {
        "key": "15-10-15-06-K001",
        "level": 5,
        "dataType": "FUEL",
        "usage": "General classification",
        "description": "Petrol 100% mineral"
      }
    ]
  }
}

Sample rows (truncated). Your environment returns the full list — always copy key values from your own response into classificationKey.

2Submit MUTATION createFuel #

Submit fuel consumption records. Use this for any liquid or gaseous fuel — petrol, diesel, marine gas oil, natural gas, LPG, biofuels — consumed by vehicles, generators, boilers, or other equipment.

MUTATIONFuelcreateFuel

Returns CreateDataPayload!

Input: CreateFuelInput! → data: [CreateSingleFuelInput!]!

You can submit one or many fuel records in data. For each record you may set one or several quantity fields among liters (litres, L), kg (kilograms), m3 (cubic metres, ), and kwh (kilowatt-hours, kWh) — for example both liters and kg when your data includes both.

ReqFieldTypeDescription
requiredexternalIdString!Your unique row ID (deduplication)
requiredtimeDateTime!When the fuel was consumed (UTC)
requiredcustomerIdString!Target Klappir customer ID
requiredclassificationKeyString!Classification key from getClassifications
requiredassetDescriptionString!Asset tied to the activity (vehicle, site, etc.). Min. length enforced by API.
requiredfuelDescriptionString!Fuel product (e.g. Diesel B7). Min. length enforced by API.
optionalsupplierLabelStringSupplier display name
optionaldeliveryPointStringDelivery point or supplier reference (truck reg., station id, vessel IMO, etc.)
requiredaddressAddressInput!Station or delivery address (see AddressInput)
optionallitersFloatVolume in litres (L)
optionalkgFloatMass in kilograms
optionalm3FloatVolume in cubic metres ()
optionalkwhFloatEnergy in kilowatt-hours (kWh)
optionalreferenceStringInvoice or internal reference

Mutation

mutation createFuel($input: CreateFuelInput!) {
  createFuel(input: $input) {
    success
    message
    rows
  }
}

Variables — one diesel record

{
  "input": {
    "data": [{
      "externalId": "YOURCO-FUEL-2024-03-001",
      "time": "2024-03-01T08:00:00.000Z",
      "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
      "classificationKey": "15-10-15-05-K001",
      "assetDescription": "Truck #14",
      "fuelDescription": "Diesel B7",
      "address": {
        "country": "IS",
        "city": "Reykjavík",
        "address": "12 Harbour Lane",
        "postalCode": "105"
      },
      "liters": 450.5,
      "kg": 382.0,
      "reference": "Invoice #4521"
    }]
  }
}

Response

{"data": {"createFuel": {"success": true, "message": "OK", "rows": 1}}}

2Submit MUTATION createCargo #

Submit upstream transportation & distribution records. Use for inbound, outbound, or internal logistics moves by road, sea, rail, or air. In the API this mutation is still named createCargo; input is data, an array of CreateSingleCargoInput.

MUTATIONUpstream transportation & distributioncreateCargo

Returns CreateDataPayload!

Fields on CreateSingleCargoInput

Use AddressInput for loadAddress and unloadAddress (see AddressInput).

ReqFieldTypeDescription
requiredexternalIdString!Your unique row ID
requireddateDateTime!Date of shipment (UTC)
requiredloadAddressAddressInput!Origin / pickup
requiredunloadAddressAddressInput!Destination / delivery
requireddistanceFloat!Distance in kilometres
requiredweightFloat!Mass in kilograms for this upstream transportation & distribution record
requiredcustomerIdString!Target customer ID
requiredclassificationKeyString!Classification key
requiredtransportTypeCargoTransportTypeEnum!INBOUND, OUTBOUND, or INTERNAL
requiredassetLabelString!Asset tied to the shipment (vehicle, site, etc.)
requireddataLabelString!Distinct label for the move (B/L, booking ref., etc.)
optionalsupplierLabelStringCarrier or forwarder name
optionalreferenceStringExtra context (invoice, notes)

Mutation

mutation createCargo($input: CreateCargoInput!) {
  createCargo(input: $input) {
    success
    message
    rows
  }
}

Variables — outbound trailer (same day)

{
  "input": {
    "data": [{
      "externalId": "YOURCO-UTD-2024-03-088",
      "date": "2024-03-08T06:00:00.000Z",
      "loadAddress": {
        "country": "IS",
        "city": "Reykjavík",
        "address": "Main depot, Sundagarðar",
        "postalCode": "104"
      },
      "unloadAddress": {
        "country": "IS",
        "city": "Keflavík",
        "address": "Keflavík logistics terminal",
        "postalCode": "235"
      },
      "distance": 52,
      "weight": 18500,
      "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
      "classificationKey": "78101802U002U001",
      "transportType": "OUTBOUND",
      "assetLabel": "Trailer T-402",
      "dataLabel": "B/L ICE-2024-7781",
      "supplierLabel": "Northwind Line",
      "reference": "INV 99204"
    }]
  }
}

Response

{"data": {"createCargo": {"success": true, "message": "OK", "rows": 1}}}

2Submit MUTATION createWaste #

Submit waste disposal records. For waste haulers and organisations self-reporting waste data. Note: createWaste returns CreateWastePayload with a status enum, unlike most mutations which return a success boolean.

Two classification keys per row

Waste records carry two classification keys — one for what the waste is (e.g. mixed paper, food waste, hazardous chemicals) and one for how it's treated (recycled, landfilled, incinerated). Both drive the emissions calculation — the same waste type has very different emissions depending on treatment.

In createWaste these map to wasteClassificationKey (what the waste is) and treatmentClassificationKey (how it is treated) on each CreateSingleWasteInput row — the same split as in the Waste CSV template.

MUTATIONWastecreateWaste

Returns CreateWastePayload! — note: different payload type

Fields on CreateSingleWasteInput

You can submit one or many waste records in data. Quantity is reported as mass in kilograms using the kg field (cubic metres / m3 are not supported for waste). Use AddressInput for the collection / pickup site (see AddressInput).

ReqFieldTypeDescription
requiredexternalIdString!Your unique row ID
requiredtimeDateTime!Pickup time (UTC)
requiredwasteDescriptionString!What was collected or disposed
requiredcustomerIdString!Target customer ID
requiredwasteClassificationKeyString!Classification key for the waste stream (from getClassifications)
requiredtreatmentClassificationKeyString!Treatment / disposal classification key
requiredkgFloat!Mass in kilograms for this row (m3 is not supported for waste)
requiredpickUpAddressAddressInput!Customer / collection site
optionalpickUpLocationStringExtra location detail (gate, bay, instructions)
optionalsupplierLabelStringWaste pickup provider name
optionalreferenceStringTicket, weighbridge, or invoice ref.

Mutation

mutation createWaste($input: CreateWasteInput!) {
  createWaste(input: $input) {
    status
    rows
  }
}

Variables — mixed waste pickup

{
  "input": {
    "data": [{
      "externalId": "YOURCO-WASTE-202403-001",
      "time": "2024-03-05T07:30:00.000Z",
      "wasteDescription": "Mixed municipal — Reykjavík depot",
      "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
      "wasteClassificationKey": "111416K01",
      "treatmentClassificationKey": "7612K02K03",
      "pickUpAddress": { "country": "IS", "city": "Reykjavík" },
      "kg": 1200
    }]
  }
}

Response

{"data": {"createWaste": {"status": "SUCCESS", "rows": 1}}}

2Submit MUTATION createFlightTravel #

Submit air travel records. For travel agencies, corporate travel management, and organisations self-reporting flight emissions. Captures origin/destination airports, cabin class, and number of passengers.

MUTATIONFlight travelcreateFlightTravel

Returns CreateDataPayload!

Fields on CreateSingleFlightTravelInput

Cabin or fare class is usually encoded in the classificationKey you choose from getClassifications.

ReqFieldTypeDescription
requiredexternalIdString!Your unique row ID
requireddateOfTravelDateTime!Flight date/time (UTC)
requiredfromIATAString!Origin airport (IATA)
requiredtoIATAString!Destination airport (IATA)
requirednumberOfPassengersInt!Passenger count
requiredtravelDescriptionString!Trip purpose or label
requiredassetDescriptionString!Asset tied to the activity (vehicle, site, etc.)
requiredcustomerIdString!Target customer ID
optionalclassificationKeyStringAir travel classification key
optionalsupplierLabelStringAgency or TMC name
optionalreferenceStringPNR, invoice, or policy ref.

Mutation

mutation createFlightTravel($input: CreateFlightTravelInput!) {
  createFlightTravel(input: $input) {
    success
    message
    rows
  }
}

Variables — flight leg KEF → CPH

{
  "input": {
    "data": [{
      "externalId": "YOURCO-FLT-2024-03-014",
      "dateOfTravel": "2024-03-12T14:20:00.000Z",
      "fromIATA": "KEF",
      "toIATA": "CPH",
      "numberOfPassengers": 1,
      "travelDescription": "Client meeting — Copenhagen",
      "assetDescription": "Sales team / EMEA",
      "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
      "classificationKey": "78111502U003U001",
      "reference": "PNR ABC123"
    }]
  }
}

Response

{"data": {"createFlightTravel": {"success": true, "message": "OK", "rows": 1}}}

2Submit MUTATION createSurfaceTravel #

Submit non-aerial transportation records. Covers road, rail, and sea travel. Use for company vehicle mileage, employee commute, ferry trips, or any surface-mode transport.

MUTATIONSurface travelcreateSurfaceTravel

Returns CreateDataPayload!

Fields on CreateSingleSurfaceTravelInput

Surface travel covers road, rail, and sea modes (for example company vehicles, buses, trains, or ferries). Use AddressInput for fromAddress and toAddress (see AddressInput).

ReqFieldTypeDescription
requiredexternalIdString!Your unique row ID
requireddateOfTravelDateTime!Trip start (UTC)
requiredfromAddressAddressInput!Origin
requiredtoAddressAddressInput!Destination
requireddistanceTraveledFloat!Distance in kilometres
requirednumberOfPassengersInt!Passenger count
requiredtravelDescriptionString!Mode and context (e.g. ferry, rail commute)
requiredassetDescriptionString!Asset tied to the activity (vehicle, site, etc.)
requiredcustomerIdString!Target customer ID
optionalclassificationKeyStringSurface travel classification key
optionalsupplierLabelStringOperator name
optionalreferenceStringTicket or invoice ref.

Mutation

mutation createSurfaceTravel($input: CreateSurfaceTravelInput!) {
  createSurfaceTravel(input: $input) {
    success
    message
    rows
  }
}

Variables — ferry leg (road + sea)

{
  "input": {
    "data": [{
      "externalId": "YOURCO-SURF-2024-03-021",
      "dateOfTravel": "2024-03-15T07:00:00.000Z",
      "fromAddress": {
        "country": "IS",
        "city": "Landeyjahöfn",
        "label": "Ferry terminal"
      },
      "toAddress": {
        "country": "IS",
        "city": "Vestmannaeyjar",
        "label": "Herjólfur dock"
      },
      "distanceTraveled": 14,
      "numberOfPassengers": 2,
      "travelDescription": "Ferry — staff site visit",
      "assetDescription": "Field operations / South",
      "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
      "classificationKey": "78111706",
      "supplierLabel": "Herjólfur",
      "reference": "Ticket H-44102"
    }]
  }
}

Response

{"data": {"createSurfaceTravel": {"success": true, "message": "OK", "rows": 1}}}

2Submit MUTATION createHotelTravel #

Submit hotel stay records. For travel agencies and organisations tracking Scope 3 business travel. Each record captures number of nights, country, and optionally hotel name and city.

MUTATIONHotel stayscreateHotelTravel

Returns CreateDataPayload!

Fields on CreateSingleHotelTravelInput

address identifies the country where the hotel is located (see AddressInput).

ReqFieldTypeDescription
requiredexternalIdString!Your unique row ID
requireddateDateTime!Check-in date (UTC)
requiredaddressAddressInput!Hotel location (at least country)
requirednumberOfNightsInt!Nights booked
requirednumberOfRoomsInt!Rooms booked
optionalnumberOfGuestsIntGuests (optional if unknown)
requiredstayDescriptionString!Free-text description of the stay — for example the hotel name, a conference or event, the customer or account you visited, or an internal project label.
requiredassetDescriptionString!Asset tied to the activity (vehicle, site, etc.)
requiredcustomerIdString!Target customer ID
optionalclassificationKeyStringHotel stay classification key
optionalsupplierLabelStringChain or booking channel
optionalreferenceStringConfirmation or invoice ref.

Mutation

mutation createHotelTravel($input: CreateHotelTravelInput!) {
  createHotelTravel(input: $input) {
    success
    message
    rows
  }
}

Variables — two-night stay in Copenhagen

{
  "input": {
    "data": [{
      "externalId": "YOURCO-HOTEL-2024-03-009",
      "date": "2024-03-18T15:00:00.000Z",
      "address": {
        "country": "DK",
        "city": "Copenhagen",
        "address": "Tivoli Hotel & Congress Centre",
        "postalCode": "1630"
      },
      "numberOfNights": 2,
      "numberOfRooms": 1,
      "numberOfGuests": 1,
      "stayDescription": "Tivoli Hotel — client workshop (EMEA sales)",
      "assetDescription": "Sales team / EMEA",
      "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
      "classificationKey": "90111801",
      "supplierLabel": "CorporateTravel.dk",
      "reference": "Conf. DK-88331"
    }]
  }
}

Response

{"data": {"createHotelTravel": {"success": true, "message": "OK", "rows": 1}}}

2Submit MUTATION createGoodsServices #

Submit purchased goods and services data. Covers Scope 3 Category 1 spend-based reporting. Each record represents monetary spend on a product or service — Klappir converts this to an emissions estimate using spend-based emission factors.

MUTATIONGoods & servicescreateGoodsServices

Returns CreateDataPayload!

Fields on CreateSingleGoodsServicesInput

Other members on CreateSingleGoodsServicesInput may exist beyond this table — confirm names and nullability with GraphQL introspection for your environment.

Each record must include at least one of kg (kilograms purchased) and kgco2e (supplier-verified CO₂e for the line item); you may send both. When both are present, Klappir uses kgco2e as the authoritative emissions value and keeps kg for traceability — the same rule as the Goods & Services CSV template.

ReqFieldTypeDescription
requiredexternalIdString!Your unique row ID
requireddateDateTime!Purchase / invoice date (UTC)
requiredproductLabelString!Product or line item as on the invoice
requiredassetDescriptionString!Asset tied to the activity (vehicle, site, etc.)
requiredclassificationKeyString!Classification key from getClassifications
requiredcustomerIdString!Target customer ID
optionalkgFloatMass purchased in kilograms (quantity path). See the note above for row-level requirements.
optionalkgco2eFloatDirect CO₂e for the line item from a supplier-verified figure (emission path). When both kg and kgco2e are sent, kgco2e is authoritative for emissions.
optionalsupplierLabelStringVendor display name
optionalreferenceStringPO, contract, or invoice ref.

Mutation

mutation createGoodsServices($input: CreateGoodsServicesInput!) {
  createGoodsServices(input: $input) {
    success
    message
    rows
  }
}

Variables — quantity + supplier CO₂e (both)

{
  "input": {
    "data": [{
      "externalId": "YOURCO-GS-2024-03-044",
      "date": "2024-03-22T00:00:00.000Z",
      "productLabel": "Wooden piling",
      "assetDescription": "HQ — Borgartún",
      "classificationKey": "30102804",
      "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
      "kg": 120,
      "kgco2e": 86.4,
      "supplierLabel": "Nordic Office Supply",
      "reference": "PO 77812"
    }]
  }
}

You can omit kgco2e and send only kg (or only kgco2e if you have a verified emissions figure without mass).

Response

{"data": {"createGoodsServices": {"success": true, "message": "OK", "rows": 1}}}

Edit, update & delete data #

The same lifecycle rules apply to the API as to SFTP. Every create* mutation is an upsert keyed by externalId (SFTP Unique ID). Send the mutation again to change a row; send quantity fields as zero to remove it. There is no separate delete mutation.

SFTP equivalent

CSV re-upload with the same Unique ID updates a row; Value = 0 deletes it. Full SFTP walkthrough: Edit / update / delete. Field mapping: SFTP and API field alignment.

Update an existing record

To correct data that already reached Klappir:

  1. Call the same create* mutation you used originally (createFuel, createWaste, and so on).
  2. Include a record object with the same externalId as before.
  3. Change any fields that need updating (time, classificationKey, quantities, addresses, labels, etc.).

Klappir updates the existing row instead of creating a duplicate. The mutation response can still show success: true — confirm the change in the Klappir platform if needed.

Delete a record

To remove a record, call the same mutation again with the same externalId and set the quantity field(s) you originally used to zero:

MutationQuantity field(s) to set to 0
createFuelThe field(s) you populated — liters, kg, m3, and/or kwh
createCargoweight and/or distanceTraveled (whichever you sent)
createWastekg
createFlightTravelpassengers (and/or distance fields if you used them)
createSurfaceTraveldistanceTraveled and/or passengers
createHotelTravelnights
createGoodsServiceskg and/or kgco2e

Omitting a record from a new batch does not delete it. Only an explicit zero-quantity resubmit with the same externalId removes the row — the same rule as on SFTP.

Example — update and delete fuel

After submitting diesel for March, you can fix a date or remove a bad row:

// Update — same externalId, corrected time
{
  "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
  "externalId": "YOURCO-FUEL-2024-03-002",
  "classificationKey": "15-10-15-05-K001",
  "time": "2024-03-02T12:00:00Z",
  "liters": 312.0
}

// Delete — same externalId, zero quantity
{
  "customerId": "afaf2111-f5cc-4c69-b806-46d318e28b5d",
  "externalId": "YOURCO-FUEL-2024-03-099",
  "classificationKey": "15-10-15-05-K001",
  "time": "2024-03-15T12:00:00Z",
  "liters": 0
}

Recommended correction workflow

StepAction
1Confirm the record exists in the Klappir platform (wrong totals often mean a failed first submit).
2Build a minimal mutation payload — one corrected or zero-quantity record is enough.
3POST the mutation; log success, message, and rows from the response.
4Verify in the platform. If it still looks wrong, see Troubleshooting common API errors.

If you submitted the same externalId twice by mistake, keep the correct row and resubmit the duplicate with liters: 0 (or the relevant zero quantity) to delete it.

What's next, after your first integration #

Once your first end-to-end run works, the next step is a reliable production pipeline. A few directions to think about:

Schedule it

Most integrations run on a cron schedule — nightly for the previous day's data. A single cron job per data type or customer is usually enough.

Handle errors gracefully

Network errors, validation failures, and transient 5xxs all happen. Retry with backoff. When success: false comes back, log the message field — it usually tells you which record failed and why.

Batch sensibly

Don't submit one record at a time. Most integrations batch by day or by customer. If a batch is too large, split on a natural boundary like customerId.

Pick a stable externalId scheme

Once you've chosen a format, don't change it. A scheme like YOURCO-FUEL-2024-03-001 pays off when reconciling or correcting historical records. To fix or remove rows later, see Edit / update / delete.

Refresh the cache periodically

getClassifications can change as the taxonomy grows. Cache aggressively but refresh on a schedule so new codes show up.

getActiveCustomers and getClassifications can change. Cache aggressively but refresh weekly so new customers and codes show up.

Monitor in the dashboard

Verify data appears in Klappir after submission. Set up alerts in your monitoring stack tied to the rows response — a sudden drop usually means upstream data is missing.

When something goes wrong

For common HTTP and GraphQL payload issues (401, validation errors, customerId, classificationKey), see the Troubleshooting common API errors table in Getting started. If you still need help, email service@klappir.com with your x-api-key identifier (not the key itself), the timestamp of the request, and the response body.

Type reference #

Key types referenced throughout the API. Standard GraphQL scalars (String, Boolean, Int, Float, ID) follow standard definitions. Tables below use the same Req column as mutation inputs: required vs optional.

Customer

ReqFieldTypeDescription
requiredidID!UUID — use as customerId in all mutations. Direct customers: same value as Settings → System → Entity IDs in the Klappir Platform.
requirednameString!Company display name
requiredregistrationString!Company registration number
optionaldescriptionStringOptional description
optionaladdressCustomerAddressPhysical address fields

CreateDataPayload

Returned by most create* mutations.

ReqFieldTypeDescription
requiredsuccessBoolean!Whether the operation succeeded
optionalmessageStringHuman-readable status or error message
optionalrowsIntNumber of records accepted

Classification

One row from getClassifications.

ReqFieldTypeDescription
requiredkeyID!Use as classificationKey / waste keys on mutations
requiredlevelInt!Hierarchy depth
requireddataTypeDataTypeEnum!Target data category
requiredusageString!Internal usage label
requireddescriptionString!Display label

GetClassificationsInput

ReqFieldTypeDescription
optionalkeyPrefixStringReturn keys starting with this prefix
optionaldataType[DataTypeEnum!]Filter to one or more data types — e.g. ["FUEL", "WASTE"]

CreateWastePayload

Returned specifically by createWaste.

ReqFieldTypeDescription
requiredstatusStatusEnum!SUCCESS or FAILURE
requiredrowsInt!Number of records accepted

DataTypeEnum

ValueDescription
FUELLiquid and gaseous fuels — createFuel, Fuel template
WASTEWaste disposal — createWaste, Waste template
FLIGHTAir travel — createFlightTravel, Flight template
SURFACE_TRAVELRoad, rail, or sea travel — createSurfaceTravel, Surface template
HOTELHotel stays — createHotelTravel, Hotel template
CARGOUpstream transportation & distribution — createCargo, Upstream template
GOODS_SERVICESPurchased goods and services — createGoodsServices, Goods & Services template

CargoTransportTypeEnum (upstream transportation & distribution)

ValueDescription
INBOUNDFreight arriving at customer's location
OUTBOUNDFreight leaving customer's location
INTERNALInternal logistics between sites

AddressInput

Nested object for structured locations on fuel, upstream transportation & distribution, hotel, surface travel, and waste collection (pickup) payloads. country is an ISO 3166-1 alpha-2 code; other members are optional text or coordinates.

ReqFieldTypeDescription
requiredcountryCountryIsoLocode!ISO country code (e.g. IS)
optionaladdressStringStreet line
optionalcityStringCity
optionalpostalCodeStringPostal or ZIP code
optionalmunicipalityStringMunicipality or district
optionallabelStringShort site label (yard, pier, building)

DateTime

ISO 8601 datetime string. Example: "2024-03-01T08:00:00.000Z". Always use UTC (suffix Z).