Self-hosted service
karrioapi/karrio avatar
karrioapi/karrio

Karrio puts every carrier API behind one HTTP surface

Programmable Shipping APIs (self-hosted)

804 stars187 forksPythonNOASSERTION

At a glance

What is it?
Karrio is a self-hosted shipping platform written in Python with a Django core and a TypeScript dashboard, built so a marketplace, ERP or 3PL can quote rates, buy labels and track packages through one set of APIs instead of one integration per carrier. Carrier reach comes from community plugins under `/community`, while multi-tenancy, workflows, audit logging and SSO live in `/ee` under a separate licence.
Who is it for?
Karrio fits platform teams that resell shipping to merchants and need carrier access, label generation and tracking on infrastructure they control, and that can commit to running a Django service plus a Node dashboard. It is the wrong choice for a single small merchant that needs one carrier and one label a day, and for teams that need the multi-tenancy, workflow, audit log or SAML features without a commercial agreement.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 122 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One HTTP surface over many carrier integrations

Karrio's pitch is that shipping integration is still painful, and it names four reasons: carrier documentation is thin, the APIs are multiple and inconsistent, getting account and API credentials for development is difficult, and the developer experience is poor. The platform is the answer to those four points. It exposes a network of shipping carriers API first, so the calling application talks to one set of endpoints and Karrio translates to each carrier's own protocol.

The functional surface is stated as a list. Headless Shipping gives API access to the carrier network. A multi-carrier API adds webhooks, APIs and metadata for building shipping functionality. Fulfil Orders covers connecting carrier accounts, getting live rates and purchasing shipping labels. Tracking creates package trackers and returns real-time tracking status. The dashboard exists to test and visualise shipping transactions, and there is also a document generation API.

Two audiences are named separately in the documentation. For platforms, Karrio is meant to be embedded into a marketplace, eCommerce site, ERP, WMS, OMS, 3PL or logistics platform so that merchants and customers get native shipping. For retailers and 3PLs, the argument is control over the shipping stack, with the note that when onboarding new carriers the IT team can meet their requirements in a week or less.

There is a stated boundary on scope. The README says outright that Karrio is not designed as an out-of-the-box shipping software to be used for purposes that differ from the feature scope above, which rules out treating it as a warehouse management system with a label printer bolted on.

Carrier reach lives in pip-installable community plugins

The carrier integrations are not hard-wired into the core. They sit in the `/community` directory as separate Python packages, and the dependency file pins each one to a version alongside the core. The listed plugins include `karrio-fedex`, `karrio-dhl-express`, `karrio-dhl-parcel-de`, `karrio-dhl-poland`, `karrio-dhl-universal`, `karrio-dpd`, `karrio-easypost`, `karrio-gls`, `karrio-purolator`, `karrio-laposte`, `karrio-sendle` and `karrio-australiapost` among others:

text
karrio-dhl-express==2026.1.32
karrio-dhl-parcel-de==2026.1.32
karrio-dhl-poland==2026.1.32
karrio-dhl-universal==2026.1.32

The core package itself is pinned as `karrio==2026.1.32`, so every plugin in that file moves in lockstep with the server. That is a good property for an upgrade, because there is no question about which plugin version pairs with which server build.

For carriers without an official plugin, the project ships a multi-carrier SDK and a `karrio-generic` package so a team can implement a custom carrier API against the same shape as the built-in ones. The top level also carries `CARRIER_INTEGRATION_GUIDE.md`, `CARRIER_INTEGRATION_FAQ.md` and `CARRIER_INTEGRATION_PROMPT_TEMPLATE.md`, plus a `carrier-testing/` directory, which is the documentation set for anyone writing that connector.

docker compose up is the shortest path to a running server

The documented quick start is a clone and a compose run. The `community` directory is a git submodule, so it has to be initialised before the server has any carrier plugins to load:

sh
git clone --depth 1 https://github.com/karrioapi/karrio
cd karrio
git submodule update --init community
cd docker
docker compose up

After that the server is on port 5002 and the dashboard on port 3002, and the README gives default login credentials of `[email protected]` with the password `demo`. The compose file in the repository root confirms the shape of the development stack: a `karriodev` service built from `docker/dev.Dockerfile` that publishes 5002, 3002 and 3005, a `caddy` service on 80 and 443 that routes to those three upstreams, and a `maildev` service on 1080 and 1025 for catching outgoing mail during development.

yaml
services:
  karriodev:
    build:
      context: .
      dockerfile: docker/dev.Dockerfile
    container_name: karrio.dev
    ports:
      - 5002:5002
      - 3002:3002
      - 3005:3005
    volumes:
      - .:/karrio

The fifth port, 3005, is the documentation service, which the compose file wires to a `DOCS_UPSTREAM` variable. Note that the mail catcher is part of the default stack: password resets and notification emails will not leave the machine while `maildev` is in place.

The one line hobby deploy asks for 4GB of memory

For a Linux host that should run without a repository checkout, the project offers a single command that pulls a deploy script and runs it:

bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/karrioapi/karrio/HEAD/bin/deploy-hobby)"

The script is referenced from the `bin/` directory of the repository, and the documentation calls this an advanced open source hobby deploy, recommending 4GB of memory and Docker on Linux. The `HEAD` ref in the URL is worth noticing: the script is fetched from the default branch rather than from a pinned tag, so two people running the same command on different days can get different behaviour. If you want a reproducible install, pin the branch to a release tag instead.

That is the practical difference between the two install paths. The clone and compose route gives you a development environment with live code mounting and a mail catcher, and it is the right one for extending Karrio. The hobby deploy is the one for a server you do not intend to modify.

The .env sample shows the knobs that decide behaviour

Configuration is environment driven, and the sample file is explicit about the defaults, which are development defaults rather than production ones. The core server block starts like this:

text
DEBUG_MODE=True
ADMIN_DASHBOARD=True
ALLOWED_HOSTS=*,localhost,127.0.0.1,api.karrio.local,app.karrio.local,karrio.local
USE_HTTPS=False
CSRF_TRUSTED_ORIGINS=http://localhost:5002,https://api.karrio.local,https://app.karrio.local

`ALLOWED_HOSTS` ships with a wildcard, `DEBUG_MODE` ships on and `USE_HTTPS` ships off. Any of those three left alone on an internet facing deployment is a problem, and they are the first lines to review before the server is exposed.

The database block defaults to SQLite for development and carries a commented PostgreSQL path:

text
DATABASE_NAME=db.sqlite3
# Uncomment below for PostgreSQL development
# DATABASE_ENGINE=postgresql
# DATABASE_USERNAME=postgres

Authentication and worker settings follow, and they carry the same warnings:

text
ALLOW_SIGNUP=True
[email protected]
ADMIN_PASSWORD=demo
text
DETACHED_WORKER=False
WORKER_IMMEDIATE_MODE=True
TRACKING_PULSE=1200
WORK_DIR=.karrio

`ALLOW_SIGNUP=True` with the `demo` password in the sample is fine on a laptop and wrong on a server. `TRACKING_PULSE=1200` is the interval at which tracking state is refreshed, and `WORK_DIR=.karrio` is where working files and the local database land.

Multi-tenancy and SSO are not in the LGPL half

The licence story is the first thing to read before planning an installation, because the repository mixes open source and commercial code. The open source components are under LGPL-3.0: the Karrio Server, described as the core shipping API server and SDK, the Community Plugins in `/community`, and the core Modules in `/modules/*`. The README states that you are free to use Karrio for any purpose, commercial or non-commercial, to self-host and modify the open source components, to build and distribute carrier plugins and integrations, and to contribute improvements back.

The `/ee` directory holds enterprise-only features under the Karrio Enterprise License, in a separate `LICENSE_EE` file. The table in the README lists four: multi-tenancy for platform level tenant isolation, advanced workflows described as a shipping automation and rules engine, audit logging for compliance and security tracking, and SSO/SAML for enterprise authentication.

That table is the decision point for a platform business. Tenant isolation is the feature a multi-merchant marketplace needs before it can put a hundred shippers on one installation, and it is not in the LGPL components. GitHub cannot classify the repository licence as a standard one because of this dual model, so anyone evaluating Karrio has to read `LICENSE` and `LICENSE_EE` directly rather than trust the badge. This is a licence identifier summary and not a legal opinion.

A Django server and a turbo driven dashboard

The implementation is split across two languages and two build systems. The Python side is a Django stack, and the dependency file shows how much of the platform is Django based: `django==6.0.6` with `djangorestframework==3.17.1`, `django-oauth-toolkit` for OAuth, `django-two-factor-auth` and `django-otp` for authentication factors, `django-redis` and `huey` for background work, `gunicorn` as the WSGI server, and `drf-spectacular` for OpenAPI schema generation.

The front end is a separate workspace tree. The root `package.json` is private and declares workspaces covering `apps/*`, `packages/*`, `ee/apps/*`, `ee/packages/*` and `ee/insiders/packages/*`, so the enterprise and insiders code sits in the same repository but in separate workspace roots. Builds run through turbo, with `turbo run build` and `turbo run dev`, plus separate `dev:oss` and `dev:platform` targets, and the package manager is pinned to `[email protected]`.

Two more directories deserve a mention. `specs/` and `schemas/` hold API specifications and schemas, `openapitools.json` suggests the schema is generated into typed clients, and `postman/` and `.postman/` hold a shared Postman collection for trying the API by hand. The `apps/` directory holds the server application itself, with `apps/api/karrio/server` referenced in the README for static assets.

What Karrio is not built to be

The clearest limits are stated by the project itself. The README says Karrio is not designed as an out-of-the-box shipping software for purposes outside its feature scope, which rules out expecting a turnkey warehouse or order management system. The philosophy paragraph adds a constraint on maintenance rather than on features: it describes a relaxed, open and positive development approach and says the project is a free tool developed and maintained by people donating their own free time.

That framing has a practical reading. The scope is APIs: rates, labels, tracking, webhooks, carrier connections and documents. Anything that needs a warehouse operator to sit in front of a screen, or a shipping desk to handle exceptions by hand, is not what this code does.

Activity is recent enough to read as current work, but the release pattern is worth noting for planning. The last push to the repository was on 2026-06-23, and the release history shows three consecutive patch releases in that window: v2026.1.32 on 2026-06-23, v2026.1.31 on 2026-04-29 and v2026.1.30 on 2026-04-28. The version format is date based, so a patch release tells you when the code went out but not how much changed. The `CHANGELOG.md` in the repository root is the place to read that before an upgrade.

Editorial conclusion

Karrio fits platform teams that resell shipping to merchants and need carrier access, label generation and tracking on infrastructure they control, and that can commit to running a Django service plus a Node dashboard. It is the wrong choice for a single small merchant that needs one carrier and one label a day, and for teams that need the multi-tenancy, workflow, audit log or SAML features without a commercial agreement. Verify first that a community plugin exists for each carrier you must support, that the `/ee` features you need are not the ones you are assuming are in the LGPL components, and that the label and document formats you require are covered by the plugins you plan to install.

Frequently asked questions

How do I run Karrio locally?

Clone the repository, initialise the `community` submodule, and start the compose stack with `docker compose up` from the `docker` directory. The server is then on `http://localhost:5002`, the dashboard on `http://localhost:3002`, and the default login is `[email protected]` with the password `demo`.

What licence does Karrio use?

The repository is dual licensed. The Karrio Server, the Community Plugins and the Modules are under LGPL-3.0, while the `/ee` directory, which holds multi-tenancy, advanced workflows, audit logging and SSO/SAML, is under the separate Karrio Enterprise License in `LICENSE_EE`.

Which shipping carriers does Karrio support?

Carriers are added as separate plugins in the `/community` directory, and the dependency file pins packages including `karrio-fedex`, `karrio-dhl-express`, `karrio-canadapost`, `karrio-purolator`, `karrio-gls` and others to the same version as the core `karrio` package. A `karrio-generic` package and the multi-carrier SDK are there for custom carrier APIs.

Can I add a carrier that Karrio does not ship?

Yes. The project provides a multi-carrier SDK for integrating custom carrier APIs, and the repository carries `CARRIER_INTEGRATION_GUIDE.md`, `CARRIER_INTEGRATION_FAQ.md` and a `carrier-testing/` directory for working on a connector.

Does Karrio need Docker to run?

The project is described as optimised for deployments using Docker, the quick start uses `docker compose up`, and the one line hobby deploy script expects Docker on Linux with a recommended 4GB of memory.

Official sources

  1. Issues
  2. karrioapi/karrio on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/karrioapi-karrio.svg)](https://hysenlabs.com/projects/karrioapi-karrio)

Was this useful?