Documentation

For intermediaries: the partner model

How white-label under our accreditation works: client selection on the FS portal, the FS webhook, the partner notification webhook, client management, billing model and contract termination.

Who this part is for

Exclusively for registered intermediaries

The partner notification webhook, client management via the API (release, pause-sending, resume-sending), the choice of billing model and termination from the application are available exclusively to the account of a registered intermediary (sprostredkovateľ). Technically they are bound to the partner record of the account under which your clients’ companies are created after the selection on the Financial Administration portal; an ordinary account gets them back as unavailable (not_a_reseller).

What an ordinary multi-tenant account has

  • One API token for all companies of the account (X-Peppol-Participant-Id header in SAPI-SK).
  • A notification webhook configured per company (GET/PUT /api/v1/companies/{id}/notifications) with the same X-Verteco-Signature signature.
  • Deregistration of its own company (POST /api/v1/companies/{id}/deregister) and per-company usage (GET /api/v1/companies/usage).
  • Companies are always managed by their owner, not by a partner: unilateral client release and the sending brake do not exist in the ordinary model.

How to become an intermediary

Fill in the application on the Become a digital postman page; we sign the Financial Administration form and file it for you. The fee is 99 € per year excluding VAT. Once you are published in the Financial Administration selection, clients select you under your brand, their companies are created under your partner account automatically and registered in the central SMP. In the test environment the intermediary registration is free of charge and you get a test partner endpoint right away.

Guide for SaaS / platforms

If you run an invoicing app, an ERP or a platform and want to connect several of your customers (tenants) to Peppol through us, you integrate once and serve N companies. The model is a proxy: your backend holds one API token (vpt_…) server-side only (never in the browser), and each of your tenants = one company with us (one token → N companies). The extended public guide with sample code, webhook signatures and a go-live checklist: peppol.verteco.digital/saas.

  1. 1

    One token, server-side

    Create an API token and keep it in a secured backend environment. All calls are made by your server (Bearer), not by the customer's browser.
  2. 2

    Tenant onboarding = creating a company

    For each customer, call POST /companies with their company registration number (IČO) / VAT ID (IČ DPH); it returns { id, status: "pending_verification" }; store the id with the tenant (for details see Companies).
    bash
    curl -X POST https://peppol.verteco.digital/api/v1/companies -H 'Authorization: Bearer vpt_8f2a…' \
    -H 'Content-Type: application/json' \
    -d '{"ico":"53412834","dic":"SK2121358349","legalName":"Firma s.r.o.",
         "street":"Príkladná 12","postalCode":"010 01","city":"Žilina","iban":"SK…"}'
  3. 3

    Activation in Peppol (a step the customer takes with the state)

    pending_verification ≠ live in Peppol. For a company to receive, the customer must select Verteco as their provider on the portal of the Financial Administration of the Slovak Republic (Finančná správa, FS), using eID; we then register the company in the SMP and its status changes to active. For a company to send, submit its verification token (Verifikačný údaj) via Sending verification (POST /companies/{id}/verification).
  4. 4

    Receiving invoices: webhook per tenant

    Set up a webhook (and/or e-mail) for each company and fetch the signing secret:
    bash
    curl -X PUT https://peppol.verteco.digital/api/v1/companies/{id}/notifications -H 'Authorization: Bearer vpt_8f2a…' \
    -H 'Content-Type: application/json' \
    -d '{"webhookUrl":"https://vasa-saas.sk/peppol/webhook","notificationEmail":"…"}'
    
    curl -X POST https://peppol.verteco.digital/api/v1/companies/{id}/webhook/secret -H 'Authorization: Bearer vpt_8f2a…'
    # → { "secret": "…" }   (store it to verify X-Verteco-Signature)
    When an invoice is received, you get a signed POST (event invoice.received), durable with retry/dead-letter. For signature verification, the payload and the „Otestovať webhook" (Test webhook) button, see Notifications & webhooks.
  5. 5

    Sending invoices

    Send the invoice (UBL Peppol BIS 3.0) through the national interface SAPI-SK 1.0: POST /sapi/document/send (OAuth2 client_credentials, client_secret = your vpt_ token). We add the Slovak tax report (TDD/C5) automatically.
  6. 6

    Usage data for re-invoicing

    GET /companies/usage?month=YYYY-MM returns the counts of sent and received documents for each of your companies separately as well as in total, in exactly the units the price list is built on, so you can re-invoice your clients directly from it. Without the parameter it returns the current month; the period is half-open and the response explicitly contains the from/to fields so you do not have to guess the month boundary. Companies with no traffic are listed with zeros.
  7. 7

    Scaling and robustness

    Paginate lists: GET /companies?page&limit as well as GET /companies/{id}/documents?page&limit (with headers such as X-Total-Count and others). Respect the per-token rate limit: during bulk onboarding, batch with backoff on 429 (Retry-After) and handle 409 ico_taken (idempotently).
Two independent “gates”: active = the company receives (set after selecting Verteco with the Financial Administration via eID, or after successful verification of the verification token via POST /companies/{id}/verification); sending-verified = the company sends (after the verification token has been submitted via the API). The webhook for a received invoice is only sent once the company is active.

FS webhook for intermediaries (integration manual)

If you are registered as an intermediary (sprostredkovateľ) (application via /sprostredkovatel/ziadost), the Financial Administration of the Slovak Republic (Finančná správa, FS) sends a notification to your webhook URL every time a client selects you on the FS portal (VPDS). This manual describes the exact contractas FS actually calls it in production (verified on live selections). FS does not publish its own public manual for the webhooks; this is what you need for the implementation.

1 · What the notification looks like + 2 · authenticity verification

🔒 The exact contract (payload, signature header) is shown after signing in

We keep integration details out of public HTML. Sign in with a free account and this part loads right here.

3 · What to do with it: forward the raw body to us

The recommended (and simplest) implementation is a raw-byte proxy: accept the POST, respond quickly, and forward the raw body bytes to your registration endpoint with us. That endpoint is created automatically once you fill in the /sprostredkovatel/ziadost form, it is active immediately, and you can see its exact URL (with your key) after logging in via GET /api/v1/resellers/me:

text
POST https://peppol.verteco.digital/peppol/webhook/reseller/{vas-kluc}
Content-Type: application/json
(body = the unchanged raw bytes from FS)

We cryptographically verify the verification_token, automatically create the company under your partner account (white-label), register it in the central SK SMP, and from that moment on we deliver e-invoices to it. You may store the contact details from the payload for your own onboarding; nothing more is needed.

4 · Operating rules (important)

FS does not retry the webhook. If delivery fails, FS does not send the message again; it only writes it to the taxpayer's electronic mailbox. Your endpoint must therefore be permanently available, respond quickly (within a few seconds, ideally with 200 before doing any processing of your own), and persist every received body first, and only then process it. On our side we store every call in a permanent audit log, so a missed selection can be reconstructed together.
  • Idempotency: the same entity may repeat the selection; processing the same DIČ (Slovak tax identification number) must be safe (it is on our side).
  • Source IP: calls come from FS infrastructure (observed from 194.1.2.13); we recommend an IP allowlist only as a supplement, not as the sole protection (FS does not guarantee the range).
  • Response: return 200 even on an internal processing error (log the error yourself); FS does not evaluate anything else.
  • Deployment order: the webhook must be live before the application is filed with FS; the first selection may arrive shortly after publication.

A reference proxy implementation is ~30 lines (accept POST → store → forward the raw bytes). If you want to verify the whole chain before FS publishes you, send a test POST to your registration endpoint; it responds safely to unknown/unsigned content and creates nothing. Questions: Support.

5 · Terminating the intermediary agreement

The intermediary agreement can also be terminated directly from within the application: the owner of the partner account, in Nastavenia poštára (Postman settings), fills in a termination request (control question + confirmation of the consequences) and confirms the notice via a link sent to them by e-mail. Upon confirmation the notice is deemed delivered; the notice period is one month and runs from the 1st day of the following month (Art. 7.1 of the Terms and Conditions of Intermediation). We file the request for removal from the list of intermediaries with the Financial Administration ourselves within 5 business days after the agreement ends (Art. 7.3); our team receives the supporting record, nothing is sent to the intermediary's clients. An unconfirmed request can be cancelled in the application. Programmatically: GET/POST/DELETE /api/v1/resellers/me/termination.

Partner account: notification webhook, client management, billing model and termination

Partner notification webhook (intermediaries)

If you are a registered intermediary (sprostredkovateľ), you do not need to configure a webhook for each company separately: a single partner notification webhook receives all events of the companies under your partner account and takes precedence over the webhooks of individual companies. Your clients therefore configure nothing; you distinguish the company by companyDic / peppolParticipantId.

GET/resellers/me/notification-webhookintermediary account

Current configuration: { url, hasSecret, events, lastRevealedAt, lastRevealedIp } (the secret is not returned).

PUT/resellers/me/notification-webhookintermediary account

Sets an https URL (max 512). On the FIRST setup a signing secret is generated and returned ONCE in the response; subsequent URL changes keep the secret and do not return it. An empty URL removes both the webhook and the secret.

FieldTypeRequiredDescription
urlstringyeshttps URL, max 512; empty string = remove
json
// 200 OK (first setup)
{ "url": "https://vasa-appka.sk/peppol/events", "secret": "vpt_…", "hasSecret": true,
"events": ["company.activated","company.deactivated","invoice.received","invoice.sent","invoice.delivered","invoice.rejected"] }
POST/resellers/me/notification-webhook/revealintermediary account + password

Re-displays the stored secret after confirmation with the account password ({ password }). Every reveal is audited and the last one is visible in GET.

The X-Verteco-Signature signature is computed the same way as for the company webhook (below), only with the partner secret.

Managing clients via the API (unilateral release and sending brake)

A client who leaves a partner usually does nothing, which is why these operations are unilateral and require no cooperation from the client. Invoice reception is not affected by them: it is tied to the company's registration in the central SMP, not to the managing account.

POST/resellers/me/clients/{companyId}/releaseintermediary account

Detaches the company from the partner account with immediate effect. The company passes under direct management by the platform; its registration, verification and invoice reception continue without interruption; from this moment on the partner is no longer billed for it. Irreversible from the partner's side.

POST/resellers/me/clients/{companyId}/pause-sendingintermediary account

Safeguard when ending a cooperation: blocks sending of the company's documents (SAPI returns 403 SAPI-AUTH-003 with the pause reason, the portal API 403 sending_paused); reception continues. Immediate effect.

POST/resellers/me/clients/{companyId}/resume-sendingintermediary account

Lifts the sending pause.

GET/resellers/me/terminationintermediary account

Status of a termination notice of the intermediary agreement filed from the application (204 = none; otherwise status awaiting_email / confirmed, contract end date contractEndsOn).

POST/resellers/me/terminationintermediary account (owner of the registration)

Files a request to terminate the agreement: body { confirmName: the exact name of the registered intermediary, reason?: string, acknowledged: true }. A confirmation link (48 h) is sent to the account owner's e-mail; the termination notice is served only once it is confirmed (Art. 7.1 of the Intermediary Terms, OP). 202 + status; 400 confirm_name_mismatch / acknowledgement_required; 409 termination_pending / termination_confirmed.

DELETE/resellers/me/terminationintermediary account

Cancels a request that has not yet been confirmed. A confirmed termination notice cannot be cancelled from the application (409); write to [email protected].

Partner billing model

In the partner console (and via GET/PUT /api/v1/resellers/me/billing) you choose the billing model (the choice is available only to registered intermediaries): per_company = €2 per month per actively sending company registration number (IČO), or per_document = €0.01 for every invoice sent by your companies (received documents are free) with a minimum monthly billing of €300 + VAT. A model change always takes effect from the 1st day of the following month (in the response pendingModel and pendingFrom); the response of both calls also returns a recalculation of the current month under both models, so you switch informed.

Recommended procedure for a terminated client (a cap on costs on your side): you can see current usage in GET /api/v1/companies/usage?month=YYYY-MM (sent/received breakdown per company, exactly for re-billing) and in GET /api/v1/resellers/me/clients (counts for the current month); in addition, an event is sent to the partner webhook for every document your companies send or receive, so you catch a "terminated" company at its very first document. Then simply call pause-sending or release.