Skip to content
Facteur

Integrations

The channel is your test framework

On this market you do not integrate an API: you install a package into your framework. We publish none yet, and this page says which one is coming, in what order and on what condition, rather than announcing five libraries that do not exist.

Today

An HTTP API, and nothing to install

That is not an admission. The waiting happens on the server and the extraction on reception, so a test needs no dependency of ours: here is a complete email verification journey, in Playwright, without a single package from us.

signup.spec.tsTypeScript
import { expect, test } from '@playwright/test';

const KEY = process.env.FACTEUR_KEY!;
const INBOX = 'j3k9x2mq';
const DOMAIN = `${INBOX}.inbox.facteur.eu`;

const awaitMessage = (sentTo: string) =>
  fetch('https://api.facteur.eu/v1/messages/search', {
    method: 'POST',
    headers: {
      authorization: `Bearer ${KEY}`,
      'content-type': 'application/json',
    },
    body: JSON.stringify({ inbox: INBOX, sentTo, wait: 30_000 }),
  }).then((response) => response.json());

test('the verification link activates the account', async ({ page }) => {
  const tag = `run-${Date.now()}`;

  // Issued before the click: it waits, and answers as
  // soon as the message lands.
  const arriving = awaitMessage(`signup+${tag}`);

  await page.goto('/signup');
  await page.getByLabel('Email').fill(`signup+${tag}@${DOMAIN}`);
  await page.getByRole('button', { name: 'Create my account' }).click();

  const { messages } = await arriving;
  const message = messages[0];

  // The status before anything derived from the body.
  expect(message.status).toBe('parsed');
  await page.goto(message.links[0].href);

  await expect(page.getByText('Account verified')).toBeVisible();
});
  • The request goes out before the click

    It waits, and answers the moment the message lands, not at the deadline. Issued after, it would be chasing a message already there.

  • Subaddressing separates the tests

    Everything after the “+” is yours. It is what lets two tests share an inbox without stealing each other’s messages.

  • status is read before any derived field

    A message is accepted before it is parsed: for a few milliseconds it has no subject, no code and no links. That is what separates “there is no code in this message” from “the code is not extracted yet”.

  • The key is read from the environment

    Never written into the test, never passed as an argument. That is the convention the plugins will keep.

What is coming

A plugin before a library, and JavaScript before anything else

The order is not negotiable along the way, and it is not a matter of taste: it follows a measurement, retaken before every delivery.

DeliverableStateWhat unlocks it
1A minimal Node library

Open an inbox, wait for a message, read it with what was extracted from it, purge. That is all, and it is deliberate: the product’s narrow scope holds for its public surface too. Zero dependencies: a test suite does not want a dependency tree.

PlannedThe foundation of the plugin, and our first publicly measurable traction.
2A Playwright plugin

A wait wired into the framework’s own engine (a fixture and an expect.poll, so neither sleep nor a retry loop), one inbox per run, destroyed at the end, and assertions that speak the language of the test: “this message carries a one-time code”, “this link leads to this domain”.

PlannedThe largest channel on the market, and nobody is in it.
3An npm create initialiser

From an empty repository to a first passing test in one command.

PlannedAn integrator’s first minute, which is the one that decides.
A Cypress plugin

A registered command returning a chainable, rather than a fixture. Eighty per cent of the work is shared with the one above.

ConditionalTrigger: the Playwright plugin shipped and documented.
A Python library

The only credible second ecosystem. We are not taking it on anticipation: the trigger is a number, not an impression.

ConditionalTrigger: steady monthly use of the Playwright plugin, and a Python request arriving through issues or support.
The other ecosystems

.NET · Ruby · PHP · Java · Go · Swift · Dart

Not on the programme, and we would rather write it down. Demand there is two to three orders of magnitude below npm, and the incumbent, who maintains ten, leaves its oldest package three major generations behind its main library. Nine libraries with no measured use are nine debts, not coverage.

Not plannedNothing. A box ticked at purchase is not an integration.

Why Playwright first

The largest channel on the market is unoccupied

Read off npm, on the date shown, and replayable by anybody.

FrameworkMonthly installsCompetitor plugin
@playwright/test201,269,570None
cypress30,638,605Two

Read on npm on 17 August 2026

None of our competitors has a Playwright plugin; two have one for Cypress. Their npm keywords still carry “selenium”, “webdriver” and “nightwatch”: their findability is a generation behind actual practice.

The honest reservation: nobody is there, and there may be a reason. Playwright’s fixtures make a plugin less indispensable than with Cypress, where registering a command is the only clean path. If, on writing it, a ten-line fixture in the documentation makes the package pointless, then the right deliverable is that documentation page, and we will say so rather than publish for the sake of publishing.

Nothing to install for a first test

A read-only key, an inbox, and the example above. The free plan asks for no card.