Where generated XML/PDF files are stored and how to protect them

Configurationwordpress2026-07-01

Goal

Know where documents generated by POP physically end up on the server, and how to prevent them from being publicly downloadable by anyone who knows (or guesses) the URL.

Storage paths

Documents generated through the POP cloud APIs (XML, PDF, and the additional formats UBL, KSeF, ZUGFeRD depending on the active channel) are cached locally to speed up downloads and reduce API credit consumption, under wp-content/uploads/, organized by year and month:

wp-content/uploads/pop-xml/YYYY/MM/
wp-content/uploads/pop-pdf/YYYY/MM/
wp-content/uploads/pop-ubl/YYYY/MM/
wp-content/uploads/pop-ksef/YYYY/MM/
wp-content/uploads/pop-zugferd/YYYY/MM/

There’s also a separate, optional setting to save a copy of the generated XML in a dedicated folder (useful for backups/external integrations): by default wp-content/uploads/pop-invoice, configurable in Advanced.

Automatic protection (Apache)

Every pop-* folder is automatically protected by POP, which creates an .htaccess file inside it:

<IfModule mod_authz_core.c>
    Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
    Deny from all
</IfModule>

This blocks direct browser access on Apache servers. The file is generated automatically on the first write to each folder: you don’t need to create it by hand.

Protection on NGINX (requires manual setup)

On NGINX servers (e.g. Kinsta, WPEngine, a VPS running NGINX) .htaccess directives aren’t read: you need an equivalent rule in the site configuration, for example:

location ~ ^/wp-content/uploads/pop-(pdf|xml|ubl|ksef|zugferd|invoice)/.*$ {
  return 403;
}

After adding it, restart NGINX to apply it.

Verify

Try opening the URL of a generated file directly in the browser (e.g. https://yoursite.com/wp-content/uploads/pop-pdf/2026/07/document.pdf): it should return a 403 (access denied) error, not the file.

Common errors

For the format and limits of the generated XML, see xml-invoices-generated.