Skip to content

Integrator onboarding

This page answers one question the rest of the guides assume you already know: which parts of an Invora integration can you set up yourself, and which ones need someone at Invora to enable?

Every other guide describes how a capability works. This one describes how you get it — and says plainly where the route does not exist yet. If a row below says No, that is a statement about today, not a promise being deferred: an aspirational entry here would recreate the exact problem this page exists to fix.

How to read the table

Yes — you can do it in the dashboard or over the API, with no Invora involvement. Partial — a route exists but it is restricted, environment limited, or only half-working; the How column says which. No — there is no self-service route today; you have to ask us.

What is self-service today

Capability Self-service today? How
Register and sign in as a human user Yes Sign up at dashboard.invora.app. Interactive apps use authorization_code + PKCE — see Authentication.
Create your organization and start a trial Yes Complete the business profile in the dashboard, or call POST /api/identity/v2/registration/complete-profile with the signed-in user's token — see Getting Started.
Create a machine user (service account) Partial Dashboard → Settings → Developer. Only an organization owner can open that page today, so a non-owner integrator cannot create one — tracked at invora-flutter#260.
Obtain a client_secret for client_credentials Partial Dashboard → Settings → Developer → Generate client secret, on the machine user. The secret is shown once and cannot be read back. Shipped for staging; not yet released to production — tracked at invora-flutter#257.
Grant that machine user its Invora.* permissions Partial Dashboard → Settings → Developer → Request API access, on the same machine user. You can only grant permissions your organization has already been delegated; if it has none, the dialog says so and enabling them is an Invora-side step — tracked at invora-flutter#257.
Mint a personal access token (PAT) or JWT key Partial Dashboard → Settings → Developer. Same owner-only restriction as creating the machine user, and PATs are for development only — tracked at invora-flutter#260.
Enable the ZATCA regulation for your tenant No Ask Invora. Enabling a regulation and setting its base configuration for a tenant is an administrator operation — see ZATCA integration. Tracked at invora/business#568.
Run ZATCA onboarding (CSR → compliance CSID → production CSID) Yes POST /api/v1/regulations/zatca/onboarding, once the regulation above is enabled and your tax identity is complete — see ZATCA integration.
Receive signed webhooks Partial Endpoints can be registered, but outbound signing is currently broken on both algorithms, so deliveries dead-letter on the first attempt. Do not build against webhook delivery yet — tracked at invora-backend#228.
Connect Tap as a payment provider Yes POST /api/billing/v2/integrations/tap with your own Tap API key — see Collect payments with Tap.

A credential with no permissions is not a working credential

A freshly created machine user holds no Invora.* permissions. Its client_credentials call will succeed and return a token, and then every API call made with that token will fail with PERMISSION_DENIED (HTTP 403). Generating the secret and granting the permissions are two separate steps — do both.

Environment matrix

These are the values every other guide refers to. Every cell below is rendered from extra.environments in guides/mkdocs.yml — the same single source the examples and the CI environment gates read — so if a page anywhere else disagrees with this table, this table is right.

Production Staging
API gateway https://gateway.invora.app https://stg-gateway.invora.app
Auth issuer https://auth.invora.app https://stg-auth.invora.app
Token endpoint https://auth.invora.app/oauth/v2/token https://stg-auth.invora.app/oauth/v2/token
Discovery document auth.invora.app/.well-known/openid-configuration stg-auth.invora.app/.well-known/openid-configuration
Dashboard https://dashboard.invora.app https://stg-dashboard.invora.app
Project-audience id 372376660185448530 372376692817133647

gRPC uses the same gateway host on port 443 over TLS — see gRPC & Transcoding.

The two reserved scopes

Machine-to-machine tokens must request both of these alongside openid. Neither is optional, and each fails differently when it is missing:

Scope What it does Symptom when missing
urn:zitadel:iam:org:project:id:<PROJECT_ID>:aud Puts the Invora project in the token's audience, which is what makes the gateway accept the token at all. <PROJECT_ID> is the project-audience id of the environment you are calling — see the table above. The gateway rejects the token.
urn:zitadel:iam:user:resourceowner Embeds the caller's home organization in the token, which is how a request with no explicit x-zitadel-orgid header resolves to your own tenant. The token is valid but the API cannot resolve a tenant, so calls return PERMISSION_DENIED (HTTP 403).

Putting it together, against production:

curl -s -X POST https://auth.invora.app/oauth/v2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET" \
  --data-urlencode "scope=openid urn:zitadel:iam:org:project:id:372376660185448530:aud urn:zitadel:iam:user:resourceowner"

Moving an example between environments changes three values

The gateway host, the auth issuer, and the project-audience id. The third is the one that gets missed: an id identifies the Invora project on a specific issuer, so presenting the staging id to the production token endpoint (or the reverse) fails with invalid_client and no token is issued. Swapping the host alone is not enough.

How machine-to-machine access is authorized

Getting an M2M credential to actually work is two independent things, and confusing them is the single most common way an integration stalls:

  1. Authentication — your machine user has a client_secret, and the token request carries both reserved scopes above. This gets you a token.
  2. Authorization — that machine user holds Invora.* project roles. This is what makes calls succeed rather than 403.

Step 2 is not automatic. Nothing grants a new machine user any Invora permission by default.

The decided direction

Invora has decided that M2M authorization should be per-tenant self-service: a dashboard action on the machine user creates the grant directly, with nobody at Invora in the loop. That is the target, and the first release of it — Generate client secret and Request API access on the Developer page — has shipped to staging (invora-flutter#257).

It is not finished, and the honest limits today are:

  • It is not yet on production — the release is on the staging line only.
  • The Developer page can only be opened by an organization owner (invora-flutter#260), so a non-owner developer cannot use it.
  • Request API access can only grant roles your organization has already been delegated. If your organization has none, the dialog tells you so and stops — the delegation itself is an Invora-side step.

Where an Invora-side step is still required

Two enablement steps have no customer-facing route at all today:

  • Delegating Invora.* roles to your organization, which is the precondition for Request API access to have anything to offer.
  • Adding a machine user to the platform's trusted-resolver allowlist. This is a hand-maintained, per-environment configuration value in Invora's internal deployment repository; a machine user listed there is granted every Invora.* permission without a per-organization role grant. It is deliberately reserved for Invora's own platform services and test clients — it is not the route a customer credential takes, it is not requestable, and it requires a commit by the Invora team. It is mentioned here only so it is clear that it exists and is not something you are missing.

Both go through the support route below.

Your tenant does not need an allowlist entry to be resolved

A machine user whose home organization is an Invora-provisioned tenant has its tenant resolved from the organization id directly, with no allowlist entry involved. Tenant resolution and permission granting are separate gates — resolving fine and still getting PERMISSION_DENIED means you are missing roles, not an allowlist entry.

Getting unblocked

There is one route today, and it is email:

  •  support@invora.app


    Enablement requests (regulation enablement, role delegation), and anything on this page marked No or Partial.

To get a useful answer on the first reply, include:

  • the environment — production or staging;
  • your organization / tenant id;
  • for an access problem, the machine user involved and the exact error (invalid_client, PERMISSION_DENIED, an HTTP status);
  • the capability from the table above that you are trying to obtain.

What we do not publish yet

There is no status page, no public issue tracker, and no documented response time for the address above. If you need a support commitment as part of a contract, raise it with your Invora contact — this page does not create one.

  • Getting Started — base URLs, protocol choice, and your first authenticated request.
  • Authentication — the OIDC flows in full, scopes, introspection, and token handling.
  • Quickstart — token to first invoice, end to end.
  • Multi-Tenancy — connected businesses, org switching, and platform models.
  • ZATCA integration — regulation onboarding and submission.
  • Webhooks — endpoint registration, signatures, and delivery guarantees.
  • Error Handling — what UNAUTHENTICATED and PERMISSION_DENIED actually mean here.