> ## Documentation Index
> Fetch the complete documentation index at: https://invopop-fi-party-endpoints.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Chargebee in France

> Route Chargebee invoices through France's e-invoicing and e-reporting flows

export const WorkflowDiagram = ({workflow}) => {
  const stateColors = {
    processing: "yellow",
    sent: "blue",
    received: "blue",
    registered: "green",
    completed: "green",
    error: "red"
  };
  const StateChip = ({state, label}) => <Badge size="sm" color={stateColors[state] || "gray"} icon="square-small" iconType="solid">
      {label.charAt(0).toUpperCase() + label.slice(1)}
    </Badge>;
  const providerIcons = {
    "silo.state": "https://silo.invopop.com/images/status.svg",
    "silo.close": "https://silo.invopop.com/images/check-badge.svg",
    "silo.if": "https://assets.invopop.com/apps/silo/if.svg",
    "silo.folder": "https://silo.invopop.com/images/folder.svg",
    "silo.modify": "https://silo.invopop.com/images/modify.svg",
    "silo.correct": "https://silo.invopop.com/images/replace.svg",
    "silo.sleep": "https://assets.invopop.com/icons/sleep.svg",
    silo: "https://assets.invopop.com/apps/silo/icon.svg",
    "sequence.enumerate": "https://sequence.invopop.com/images/enumerate.svg",
    "transform.job.create": "https://transform.invopop.com/images/jobs.svg",
    webhook: "https://webhook.invopop.com/icon.svg",
    lookup: "https://lookup.invopop.com/icon.png",
    dropbox: "https://dropbox.invopop.com/icon.png",
    pdf: "https://pdf.invopop.com/file-pdf.svg",
    peppol: "https://assets.invopop.com/apps/peppol/icon.svg",
    ubl: "https://assets.invopop.com/apps/ubl/logo.svg",
    cii: "https://assets.invopop.com/apps/cii/logo.svg",
    "gov-dk": "https://assets.invopop.com/flags/dk.svg",
    "gov-fi": "https://assets.invopop.com/flags/fi.svg",
    "gov-fr": "https://assets.invopop.com/flags/fr.svg",
    "chorus-pro": "https://assets.invopop.com/apps/chroruspro/icon.svg",
    "gov-es": "https://assets.invopop.com/apps/gov-es/icon.svg",
    "gov-es.sii": "https://assets.invopop.com/apps/sii/icon.svg",
    "gov-es.ticketbai": "https://assets.invopop.com/apps/ticketbai/icon.svg",
    "gov-es.facturae": "https://assets.invopop.com/apps/facturae/icon.svg",
    verifactu: "https://assets.invopop.com/apps/verifactu/icon.svg",
    "gov-pl": "https://assets.invopop.com/apps/ksef/icon.svg",
    "gov-sa": "https://assets.invopop.com/apps/zatca/icon.svg",
    "gov-ar": "https://assets.invopop.com/apps/arca/icon.svg",
    "at-pt": "https://assets.invopop.com/apps/at-pt/icon.svg",
    "sat-mx": "https://assets.invopop.com/apps/sat-mexico/icon.svg",
    "sw-sapien": "https://assets.invopop.com/apps/sw-sapien/icon.svg",
    "sdi-it": "https://assets.invopop.com/apps/sdi-italy/icon.svg",
    "ticket-it": "https://assets.invopop.com/apps/agenzia-entrate/icon.svg",
    "nfe-br": "https://assets.invopop.com/apps/notas-fiscais-eletronicas-brazil/icon.svg",
    chargebee: "https://assets.invopop.com/apps/chargebee/icon.svg",
    stripe: "https://assets.invopop.com/apps/stripe/icon.svg",
    email: "https://assets.invopop.com/apps/email/icon.svg",
    cron: "https://assets.invopop.com/apps/cron/icon.svg",
    ilyda: "https://assets.invopop.com/apps/ilyda/icon.svg",
    invoicexpress: "https://assets.invopop.com/apps/invoicexpress/icon.svg",
    plemsi: "https://assets.invopop.com/flags/co.svg"
  };
  const iconFor = provider => {
    const parts = (provider || "").split(".");
    for (let i = parts.length; i > 0; i--) {
      const url = providerIcons[parts.slice(0, i).join(".")];
      if (url) return url;
    }
    return null;
  };
  const StepIcon = ({provider}) => {
    const url = iconFor(provider);
    return <span title={provider} className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md border border-gray-950/10 bg-white dark:border-white/10 dark:bg-white/5">
        {url ? <img src={url} alt="" className="h-4 w-4" /> : null}
      </span>;
  };
  const renderSummary = summary => {
    const nodes = [];
    const re = /`([^`]+)`(\{[^}]*\})?/g;
    let last = 0;
    let m;
    let k = 0;
    while ((m = re.exec(summary)) !== null) {
      if (m.index > last) nodes.push(summary.slice(last, m.index));
      const attrs = m[2] || "";
      if (attrs.indexOf(".state") >= 0) {
        const state = (attrs.match(/\.state\s+\.([\w-]+)/) || [])[1] || m[1];
        nodes.push(<StateChip key={k++} state={state} label={m[1]} />);
      } else if (attrs) {
        nodes.push(<span key={k++} className="text-sm font-medium text-gray-700 dark:text-gray-300">
            {m[1]}
          </span>);
      } else {
        nodes.push(<code key={k++} className="text-sm rounded bg-gray-100 px-1 font-mono text-sm dark:bg-white/10">
            {m[1]}
          </code>);
      }
      last = m.index + m[0].length;
    }
    if (last < summary.length) nodes.push(summary.slice(last));
    return nodes;
  };
  const NoteRow = ({text}) => <div className="mt-4 mb-1 font-mono text-sm leading-5 text-gray-400 dark:text-gray-500">{"// " + text}</div>;
  const renderSteps = (steps, counter) => (steps || []).map(step => {
    counter.n += 1;
    const n = counter.n;
    const branches = (step.next || []).filter(b => b.steps && b.steps.length > 0);
    return <div key={step.id || "step-" + n}>
          {step.notes ? <NoteRow text={step.notes} /> : null}
          <div className="mt-2.5 flex items-center">
            <span className="absolute left-0 w-10 text-center font-mono text-sm text-gray-400 select-none dark:text-gray-500">
              {n}
            </span>
            <div className="flex min-w-0 flex-1 items-center gap-2 rounded-xl border border-gray-950/5 bg-white px-2 py-2 dark:border-white/10 dark:bg-gray-900">
              <StepIcon provider={step.provider} />
              <span className="text-sm shrink-0 font-medium text-gray-900 dark:text-gray-100">{step.name}</span>
              {step.summary ? <span className="text-sm min-w-0 truncate text-gray-500 dark:text-gray-400">{renderSummary(step.summary)}</span> : null}
            </div>
          </div>
          {branches.length > 0 ? <div className="ml-5 border-l border-gray-200 -my-1 py-1 pl-6 dark:border-white/10">
              {branches.map((branch, bi) => <div key={branch.code || branch.status || bi}>
                  <div className="mt-4">
                    <span className="rounded-md bg-gray-200/70 px-2 py-1 font-mono text-sm text-gray-600 dark:bg-white/10 dark:text-gray-300">
                      {branch.code || branch.status}
                    </span>
                  </div>
                  {renderSteps(branch.steps, counter)}
                </div>)}
            </div> : null}
        </div>;
  });
  const counter = {
    n: 0
  };
  const wf = workflow || ({});
  return <div className="not-prose relative my-5 rounded-2xl border border-gray-950/5 bg-gray-50 py-3 pr-4 pb-5 pl-12 dark:border-white/10 dark:bg-white/[0.03]">
      {renderSteps(wf.steps, counter)}
      {wf.rescue && wf.rescue.length > 0 ? <div className="mt-6 border-t border-dashed border-gray-300 dark:border-white/10">
          <NoteRow text="If any step fails" />
          {renderSteps(wf.rescue, counter)}
        </div> : null}
    </div>;
};

export const chargebeeCbFranceWorkflow = {
  "name": "Chargebee France send invoice",
  "description": "Sync from Chargebee and forward to PPF or record for reporting",
  "schema": "bill/invoice",
  "steps": [{
    "id": "30960320-a44d-11f0-b23b-fd08a0f26c87",
    "name": "Import Chargebee document",
    "provider": "chargebee.import"
  }, {
    "id": "66cdc390-485f-11f1-86b7-9745cc4d2380",
    "name": "Download PDF",
    "provider": "chargebee.pdf.download"
  }, {
    "id": "33e23480-10ab-11f0-a09e-7b63571a4ae2",
    "name": "Set state",
    "provider": "silo.state",
    "summary": "Set state to `processing`{.state .processing}",
    "config": {
      "state": "processing"
    }
  }, {
    "id": "eea78ac0-26f0-11f1-9156-e518ebabd527",
    "name": "Add billing mode",
    "provider": "silo.modify",
    "notes": "S2 (already-paid) ONLY when fully paid (totals.advance == total_with_tax); else S1. S2 also adds payment.terms due_dates (BR-FR-CO-09). Reads .totals.advance (NOT the old .advances bug).",
    "summary": "Modifications configured",
    "config": {
      "jq": ".tax.ext = (.tax.ext // {})\n| .tax.point = \"issue\"\n| if ((.totals.advance // null) != null and (.totals.advance == .totals.total_with_tax)) then\n    .tax.ext[\"fr-ctc-billing-mode\"] = \"S2\"\n    | .payment = (.payment // {})\n    | .payment.terms = (.payment.terms // {\"due_dates\":[{\"date\":.issue_date,\"percent\":\"100%\"}]})\n  else\n    .tax.ext[\"fr-ctc-billing-mode\"] = \"S1\"\n  end",
      "merge_type": "application/jq",
      "scope": "doc"
    }
  }, {
    "id": "4f427d80-a44d-11f0-b23b-fd08a0f26c87",
    "name": "Add VATEX",
    "provider": "silo.modify",
    "summary": "Modifications configured",
    "config": {
      "jq": ".lines |= map(\n  .taxes |= map(\n    (.ext[\"untdid-tax-category\"]? as $cat\n     | if $cat then\n         {\n           key: {\n             \"AE\": \"reverse-charge\",\n             \"E\": \"export\",\n             \"G\": \"export\",\n             \"O\": \"outside-scope\",\n             \"K\": \"intra-community\"\n           }[$cat],\n           vatex: {\n             \"AE\": \"VATEX-EU-AE\",\n             \"G\": \"VATEX-EU-G\",\n             \"O\": \"VATEX-EU-O\",\n             \"K\": \"VATEX-EU-IC\"\n           }[$cat]\n         } as $m\n\n         | if $m.key then .key = $m.key else . end\n         | if $m.vatex then\n             .ext = ((.ext // {}) + {\"cef-vatex\": $m.vatex})\n           else\n             .\n           end\n       else\n         .\n       end\n    )\n  )\n)",
      "merge_type": "application/jq",
      "scope": "doc",
      "sign": false
    }
  }, {
    "id": "7dad54c0-154a-11f0-8028-c1ed648b57b5",
    "name": "Add bank details",
    "provider": "silo.modify",
    "notes": "Normalizes the payment key to SEPA credit transfer format",
    "summary": "Modifications configured",
    "config": {
      "allow_invalid_json": false,
      "data": {
        "doc": {
          "payment": {
            "instructions": {
              "credit_transfer": [{
                "bic": "",
                "iban": ""
              }],
              "key": "credit-transfer"
            }
          }
        }
      },
      "expr": "(doc?.payment?.instructions == nil || doc?.payment?.instructions?.key == \"credit-transfer\")\n&& doc?.payment?.terms?.due_dates != nil",
      "merge_type": "application/merge-patch+json",
      "sign": false
    }
  }, {
    "id": "fb06b190-10aa-11f0-a09e-7b63571a4ae2",
    "name": "Sign envelope",
    "provider": "silo.close"
  }, {
    "id": "de2407b0-5e94-11f1-90fe-f3d836f89160",
    "name": "Lookup in Directory",
    "provider": "gov-fr.directory.lookup",
    "next": [{
      "status": "NA",
      "code": "found",
      "steps": [{
        "id": "3ffd50e0-5e95-11f1-90fe-f3d836f89160",
        "name": "Add flow2 addon",
        "provider": "silo.modify",
        "summary": "Modifications configured",
        "config": {
          "addons": ["fr-ctc-flow2-v1"]
        }
      }, {
        "id": "1f8bf500-5e95-11f1-90fe-f3d836f89160",
        "name": "Generate UBL document",
        "provider": "ubl.generate",
        "summary": "Peppol France CIUS UBL Invoice/CreditNote",
        "config": {
          "attach_invoice_pdf": false,
          "doc_type": "peppol-fr-cius",
          "private": false
        }
      }, {
        "id": "9e22f4a0-485f-11f1-86b7-9745cc4d2380",
        "name": "Record document for e-invoicing",
        "provider": "gov-fr.directory.record"
      }, {
        "id": "285c9450-5e95-11f1-90fe-f3d836f89160",
        "name": "Send Peppol Document",
        "provider": "peppol.send"
      }, {
        "id": "2d6926c0-5e95-11f1-90fe-f3d836f89160",
        "name": "Forward document to PPF",
        "provider": "gov-fr.directory.forward"
      }]
    }, {
      "status": "NA",
      "code": "not-found",
      "steps": [{
        "id": "5cff2420-7470-11f1-9deb-cda1ffc5317f",
        "name": "Add flow10 addon",
        "provider": "silo.modify",
        "summary": "Modifications configured",
        "config": {
          "addons": ["fr-ctc-flow10-v1"]
        }
      }, {
        "id": "3a023fc0-5e95-11f1-90fe-f3d836f89160",
        "name": "Record document for reporting",
        "provider": "gov-fr.reporting.record"
      }, {
        "id": "aaf85b90-6996-11f1-8722-e7a7821bd54f",
        "name": "Verify invoice can be sent",
        "provider": "peppol.has.inboxes",
        "next": [{
          "status": "NA",
          "code": "true",
          "steps": [{
            "id": "afcc78e0-6996-11f1-8722-e7a7821bd54f",
            "name": "Generate UBL document",
            "provider": "ubl.generate",
            "summary": "Peppol BIS Billing UBL Invoice/CreditNote V3",
            "config": {
              "attach_invoice_pdf": false,
              "doc_type": "bis-invoice-v3",
              "private": false
            }
          }, {
            "id": "b798c790-6996-11f1-8722-e7a7821bd54f",
            "name": "Send Peppol document",
            "provider": "peppol.send"
          }]
        }, {
          "status": "NA",
          "code": "false"
        }]
      }]
    }]
  }, {
    "id": "3037a310-10ab-11f0-a09e-7b63571a4ae2",
    "name": "Set state",
    "provider": "silo.state",
    "summary": "Set state to `sent`{.state .sent}",
    "config": {
      "state": "sent"
    }
  }, {
    "id": "354dbed0-a44d-11f0-b23b-fd08a0f26c87",
    "name": "Update Chargebee",
    "provider": "chargebee",
    "config": {
      "document_select": "xml"
    }
  }],
  "rescue": [{
    "id": "39513240-10ab-11f0-a09e-7b63571a4ae2",
    "name": "Set state",
    "provider": "silo.state",
    "summary": "Set state to `error`{.state .error}",
    "config": {
      "state": "error"
    }
  }, {
    "id": "38fd0b30-a44d-11f0-b23b-fd08a0f26c87",
    "name": "Update Chargebee",
    "provider": "chargebee",
    "config": {
      "document_select": "xml"
    }
  }]
};

France runs two parallel flows, and which one an invoice takes depends on whether the customer is registered in the **Annuaire** (the French directory).

* Customers subject to VAT in France are handled through the [e-invoicing flow](/guides/fr-pa-invoicing#sending) for domestic B2B transactions, with [status updates](/guides/fr-pa-status) reported back throughout.
* Customers not subject to VAT in France — international or B2C transactions, and territories excluded from the mandate such as Guyane, Mayotte, New Caledonia and French Polynesia — go through [e-reporting](/guides/fr-pa-reporting) instead.

This guide assumes you have already connected the Chargebee app and completed the general setup — see the [Chargebee overview](/guides/chargebee) first if you haven't.

**Required apps:** [France](/apps/france), [Peppol](/apps/peppol), [OASIS UBL](/apps/oasis-ubl)

<Info>
  Before processing any invoices, you must register your supplier in the Annuaire through Invopop. See the [registration guide](/guides/fr-pa-registration) for the e-invoicing flow and the [e-reporting registration steps](/guides/fr-pa-reporting#registration) for the reporting flow.
</Info>

## Workflow

A single template covers both French flows and picks between them automatically from the result of the **Lookup in Directory** step.

* **found** result means the customer is subject to e-invoicing, so Invopop records the document in the Annuaire, forwards it to the PPF, and sends it over Peppol.
* **not found** result means the transaction falls outside domestic e-invoicing — international B2B, B2C, or a customer in a territory excluded from the mandate — so it is recorded for e-reporting. For those, the **Can Send** action checks whether the customer is reachable on the Peppol network: if it is (a Belgian party, for example), the workflow sends the invoice over Peppol as well.

<Card title="Chargebee France" icon="code-branch" iconType="duotone" href="https://console.invopop.com/redirect/workflows/new?template=chargebee-cb-france" horizontal>
  Add to my workspace →
</Card>

<Tabs>
  <Tab title="Workflow">
    <WorkflowDiagram workflow={chargebeeCbFranceWorkflow} />
  </Tab>

  <Tab title="Code">
    <Note>
      The two paths differ in the addon and format they apply: the e-invoicing path applies the `fr-ctc-flow2-v1` addon and generates a Peppol France CIUS UBL, while the e-reporting path applies `fr-ctc-flow10-v1` and, when the customer is reachable on Peppol, generates a Peppol BIS Billing v3 document.
    </Note>

    <Note>
      The **Add bank details** step includes placeholder `bic` and `iban` fields that you must fill in with your own banking details. It only applies when the invoice carries payment due dates and the payment key is a plain `credit-transfer`, normalizing it to the SEPA format France expects. If you don't need to include payment instructions, you can remove this step.
    </Note>

    <Note>
      The **Add Billing Mode** step sets the French CTC billing mode: `S2` when the invoice is fully paid (an advance equal to the total), otherwise `S1`. The subsequent **Add VATEX** step maps UNTDID tax categories onto the GOBL tax keys and adds the `VATEX` exemption codes required by the French format.
    </Note>

    ```json Chargebee France send invoice workflow theme={"system"}
    {
        "name": "Chargebee France send invoice",
        "description": "Sync from Chargebee and forward to PPF or record for reporting",
        "schema": "bill/invoice",
        "steps": [
            {
                "id": "30960320-a44d-11f0-b23b-fd08a0f26c87",
                "name": "Import Chargebee document",
                "provider": "chargebee.import"
            },
            {
                "id": "66cdc390-485f-11f1-86b7-9745cc4d2380",
                "name": "Download PDF",
                "provider": "chargebee.pdf.download"
            },
            {
                "id": "33e23480-10ab-11f0-a09e-7b63571a4ae2",
                "name": "Set state",
                "provider": "silo.state",
                "summary": "Set state to `processing`{.state .processing}",
                "config": {
                    "state": "processing"
                }
            },
            {
                "id": "eea78ac0-26f0-11f1-9156-e518ebabd527",
                "name": "Add billing mode",
                "provider": "silo.modify",
                "notes": "S2 (already-paid) ONLY when fully paid (totals.advance == total_with_tax); else S1. S2 also adds payment.terms due_dates (BR-FR-CO-09). Reads .totals.advance (NOT the old .advances bug).",
                "summary": "Modifications configured",
                "config": {
                    "jq": ".tax.ext = (.tax.ext // {})\n| .tax.point = \"issue\"\n| if ((.totals.advance // null) != null and (.totals.advance == .totals.total_with_tax)) then\n    .tax.ext[\"fr-ctc-billing-mode\"] = \"S2\"\n    | .payment = (.payment // {})\n    | .payment.terms = (.payment.terms // {\"due_dates\":[{\"date\":.issue_date,\"percent\":\"100%\"}]})\n  else\n    .tax.ext[\"fr-ctc-billing-mode\"] = \"S1\"\n  end",
                    "merge_type": "application/jq",
                    "scope": "doc"
                }
            },
            {
                "id": "4f427d80-a44d-11f0-b23b-fd08a0f26c87",
                "name": "Add VATEX",
                "provider": "silo.modify",
                "summary": "Modifications configured",
                "config": {
                    "jq": ".lines |= map(\n  .taxes |= map(\n    (.ext[\"untdid-tax-category\"]? as $cat\n     | if $cat then\n         {\n           key: {\n             \"AE\": \"reverse-charge\",\n             \"E\": \"export\",\n             \"G\": \"export\",\n             \"O\": \"outside-scope\",\n             \"K\": \"intra-community\"\n           }[$cat],\n           vatex: {\n             \"AE\": \"VATEX-EU-AE\",\n             \"G\": \"VATEX-EU-G\",\n             \"O\": \"VATEX-EU-O\",\n             \"K\": \"VATEX-EU-IC\"\n           }[$cat]\n         } as $m\n\n         | if $m.key then .key = $m.key else . end\n         | if $m.vatex then\n             .ext = ((.ext // {}) + {\"cef-vatex\": $m.vatex})\n           else\n             .\n           end\n       else\n         .\n       end\n    )\n  )\n)",
                    "merge_type": "application/jq",
                    "scope": "doc",
                    "sign": false
                }
            },
            {
                "id": "7dad54c0-154a-11f0-8028-c1ed648b57b5",
                "name": "Add bank details",
                "provider": "silo.modify",
                "notes": "Normalizes the payment key to SEPA credit transfer format",
                "summary": "Modifications configured",
                "config": {
                    "allow_invalid_json": false,
                    "data": {
                        "doc": {
                            "payment": {
                                "instructions": {
                                    "credit_transfer": [
                                        {
                                            "bic": "",
                                            "iban": ""
                                        }
                                    ],
                                    "key": "credit-transfer"
                                }
                            }
                        }
                    },
                    "expr": "(doc?.payment?.instructions == nil || doc?.payment?.instructions?.key == \"credit-transfer\")\n&& doc?.payment?.terms?.due_dates != nil",
                    "merge_type": "application/merge-patch+json",
                    "sign": false
                }
            },
            {
                "id": "fb06b190-10aa-11f0-a09e-7b63571a4ae2",
                "name": "Sign envelope",
                "provider": "silo.close"
            },
            {
                "id": "de2407b0-5e94-11f1-90fe-f3d836f89160",
                "name": "Lookup in Directory",
                "provider": "gov-fr.directory.lookup",
                "next": [
                    {
                        "status": "NA",
                        "code": "found",
                        "steps": [
                            {
                                "id": "3ffd50e0-5e95-11f1-90fe-f3d836f89160",
                                "name": "Add flow2 addon",
                                "provider": "silo.modify",
                                "summary": "Modifications configured",
                                "config": {
                                    "addons": [
                                        "fr-ctc-flow2-v1"
                                    ]
                                }
                            },
                            {
                                "id": "1f8bf500-5e95-11f1-90fe-f3d836f89160",
                                "name": "Generate UBL document",
                                "provider": "ubl.generate",
                                "summary": "Peppol France CIUS UBL Invoice/CreditNote",
                                "config": {
                                    "attach_invoice_pdf": false,
                                    "doc_type": "peppol-fr-cius",
                                    "private": false
                                }
                            },
                            {
                                "id": "9e22f4a0-485f-11f1-86b7-9745cc4d2380",
                                "name": "Record document for e-invoicing",
                                "provider": "gov-fr.directory.record"
                            },
                            {
                                "id": "285c9450-5e95-11f1-90fe-f3d836f89160",
                                "name": "Send Peppol Document",
                                "provider": "peppol.send"
                            },
                            {
                                "id": "2d6926c0-5e95-11f1-90fe-f3d836f89160",
                                "name": "Forward document to PPF",
                                "provider": "gov-fr.directory.forward"
                            }
                        ]
                    },
                    {
                        "status": "NA",
                        "code": "not-found",
                        "steps": [
                            {
                                "id": "5cff2420-7470-11f1-9deb-cda1ffc5317f",
                                "name": "Add flow10 addon",
                                "provider": "silo.modify",
                                "summary": "Modifications configured",
                                "config": {
                                    "addons": [
                                        "fr-ctc-flow10-v1"
                                    ]
                                }
                            },
                            {
                                "id": "3a023fc0-5e95-11f1-90fe-f3d836f89160",
                                "name": "Record document for reporting",
                                "provider": "gov-fr.reporting.record"
                            },
                            {
                                "id": "aaf85b90-6996-11f1-8722-e7a7821bd54f",
                                "name": "Verify invoice can be sent",
                                "provider": "peppol.has.inboxes",
                                "next": [
                                    {
                                        "status": "NA",
                                        "code": "true",
                                        "steps": [
                                            {
                                                "id": "afcc78e0-6996-11f1-8722-e7a7821bd54f",
                                                "name": "Generate UBL document",
                                                "provider": "ubl.generate",
                                                "summary": "Peppol BIS Billing UBL Invoice/CreditNote V3",
                                                "config": {
                                                    "attach_invoice_pdf": false,
                                                    "doc_type": "bis-invoice-v3",
                                                    "private": false
                                                }
                                            },
                                            {
                                                "id": "b798c790-6996-11f1-8722-e7a7821bd54f",
                                                "name": "Send Peppol document",
                                                "provider": "peppol.send"
                                            }
                                        ]
                                    },
                                    {
                                        "status": "NA",
                                        "code": "false"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            },
            {
                "id": "3037a310-10ab-11f0-a09e-7b63571a4ae2",
                "name": "Set state",
                "provider": "silo.state",
                "summary": "Set state to `sent`{.state .sent}",
                "config": {
                    "state": "sent"
                }
            },
            {
                "id": "354dbed0-a44d-11f0-b23b-fd08a0f26c87",
                "name": "Update Chargebee",
                "provider": "chargebee",
                "config": {
                    "document_select": "xml"
                }
            }
        ],
        "rescue": [
            {
                "id": "39513240-10ab-11f0-a09e-7b63571a4ae2",
                "name": "Set state",
                "provider": "silo.state",
                "summary": "Set state to `error`{.state .error}",
                "config": {
                    "state": "error"
                }
            },
            {
                "id": "38fd0b30-a44d-11f0-b23b-fd08a0f26c87",
                "name": "Update Chargebee",
                "provider": "chargebee",
                "config": {
                    "document_select": "xml"
                }
            }
        ]
    }
    ```
  </Tab>
</Tabs>

## Customer routing & identifiers

A single SIREN registered in the Annuaire can have several directory entries, registered under the same or different Plateformes Agréées. Each entry has a unique identifier — mapped to the Peppol inbox — in one of the `SIREN`, `SIREN_SIRET`, `SIREN_SIRET_suffix` or `SIREN_suffix` forms. When no Peppol inbox is set on the customer, Invopop defaults to `0225:SIREN`, ignoring any SIRET present in the customer's identities.

Use the custom fields below to control this. Set the **Peppol inbox** to target a specific directory entry, or provide the customer's **SIREN** and **SIRET** so the directory lookup can resolve them. All three are configured as **Single line text** custom fields (or as metadata, using the hyphenated key):

| Field | Metadata key | Custom field key | Example |
| - | - | - | - |
| Peppol inbox | `gobl-customer-inbox-peppol` | `cf_gobl_customer_inbox_peppol` | `0225:123456789_test` |
| SIREN | `gobl-customer-identity-SIREN` | `cf_gobl_customer_identity_SIREN` | `123456789` |
| SIRET | `gobl-customer-identity-SIRET` | `cf_gobl_customer_identity_SIRET` | `12345678900011` |

## E-reporting transaction fields

The e-reporting path applies the `fr-ctc-flow10-v1` addon, which defines two invoice tax extensions. By default, the addon sets the billing mode to `M1` — or `M2` when the invoice is fully paid — and the B2C transaction category to `TNT1`. Use the custom fields below to override these defaults:

| Field | Metadata key | Custom field key | Example |
| - | - | - | - |
| Billing mode | `gobl-tax-fr-ctc-billing-mode` | `cf_gobl_tax_fr_ctc_billing_mode` | `S1` |
| B2C transaction category | `gobl-tax-fr-ctc-flow10-b2c-category` | `cf_gobl_tax_fr_ctc_flow10_b2c_category` | `TPS1` |

<Note>
  The metadata keys listed above follow the Chargebee metadata format (hyphens, no `cf_` prefix). If you prefer to use custom fields instead, replace hyphens with underscores and add the `cf_` prefix. See [Custom fields & metadata](/guides/chargebee#custom-fields-metadata) for details.
</Note>

## FAQ

<AccordionGroup>
  <Accordion title="How do I configure my workspace for French invoicing?">
    Two channels depending on the recipient: B2G uses Chorus Pro (CII format); B2B from September 2026 uses the Plateforme Agréée model (UBL, CII, or Factur-X via Peppol). Invopop is an approved PA — install the France PA app for B2B and the Chorus Pro app for B2G.
  </Accordion>

  <Accordion title="How can I view an XML attached to a PDF?">
    In Factur-X PDFs, the XML file is embedded within the PDF itself. To extract and view it, use the `Attachments` section in Adobe Acrobat Reader, or a tool like the [SysTools PDF Extractor](https://www.systoolsgroup.com/pdf/extractor/).
  </Accordion>

  <Accordion title="Is Invopop ready for the September 2026 mandate?">
    Invopop is an [officially approved Plateforme Agréée](https://www.impots.gouv.fr/je-consulte-la-liste-des-plateformes-agreees) under the DGFiP mandate. Registration, invoicing, and lifecycle status are available today; e-reporting (Flow 10) is in active development. See the [PA hub readiness matrix](/guides/fr-pa) for the current state.
  </Accordion>

  <Accordion title="What GOBL addons are required for France PA?">
    The base [FR tax regime](https://docs.gobl.org/regimes/fr) plus the EN 16931 profile. For Peppol delivery, `peppol-bis-v3`. The forthcoming `fr-ctc-flow10-v1` addon covers e-reporting payloads — separate from the e-invoicing flow.
  </Accordion>

  <Accordion title="Is a self-billed invoice a different document type in France?">
    No. Most Peppol countries treat self-billing as a document type of its own, but France models it as a **standard invoice** with the `untdid-document-type` extension set to `389`. In GOBL you never set the code yourself: add the `self-billed` tag and the [`fr-ctc-flow2-v1`](https://docs.gobl.org/addons/fr-ctc-flow2-v1#standard-self-billed) add-on applies it automatically. See [Self-billing](/guides/fr-pa-invoicing#self-billing) for the full flow.
  </Accordion>

  <Accordion title="How many pops does a B2B e-invoice through France PA cost?">
    Each invoice or lifecycle status sent through France PA costs **5 pops**: 1 pop for the conversion to UBL/CII, 2 pops to send it over Peppol, 1 pop to forward it to the PPF, and 1 pop for the silo entry. See [Pops & pricing](/get-started/pricing) for how pops work.
  </Accordion>

  <Accordion title="What does the record document step check against the Annuaire?">
    Before an invoice is recorded, the **PPF record document** step looks up both the supplier and the customer SIREN in the Annuaire. What each party must satisfy depends on the workflow's role:

    | Role | Annuaire state | Outcome |
    | - | - | - |
    | Both | The SIREN has no effective entry | **Rejected** |
    | Receiving | The SIREN has at least one effective entry | **Accepted** |
    | Sending | The SIREN's only entry is the PPF's default line (matricule `9998`) | **Accepted** |
    | Sending | The party's `0225` peppol endpoint matches one of the SIREN's entries | **Accepted** |
    | Sending | The party's `0225` peppol endpoint matches none of the SIREN's entries | **Rejected** |

    Sandbox invoices skip the Annuaire check entirely.
  </Accordion>

  <Accordion title="What should I do if the customer isn't registered in the Annuaire?">
    Don't block the sale. An exchange where only one party has an
    effective Annuaire entry is a
    [non-regulated flow](/guides/fr-pa#key-concepts): it leaves
    e-invoicing (flux 2) and is covered by
    [e-reporting](/guides/fr-pa-reporting) (flux 10) instead.

    In practice:

    * Run a [Directory lookup](/guides/fr-lookup) against the
      customer's SIREN before you generate the invoice — ideally in a
      separate validation workflow run against customer data, so you
      can prompt them to fix their registration ahead of time.
    * If the SIREN has no effective entry, route the invoice through
      your reporting workflow rather than the PA send workflow.
    * If it slips through, the send workflow degrades rather than
      failing: the **Verify document can be sent** step branches and
      forwards the invoice to the PPF as *déposée – non transmise*.

    A missing entry is common and not necessarily an error. A SIREN
    visible in the public
    [annuaire-entreprises](https://annuaire-entreprises.data.gouv.fr)
    registry is not the same as an effective entry in the DGFiP
    Annuaire, which only covers entities in scope of the mandate. It
    can also be absent because the buyer hasn't yet appointed a PA, or
    because their tax records don't match.
  </Accordion>

  <Accordion title="Should I check the Annuaire at order time or at invoice time?">
    Both, for different reasons. A lookup at order or onboarding time
    is a data-quality check: it lets you warn the customer and get
    their SIREN or PA sorted before invoicing. A lookup at invoice
    time is the one that decides the flow, because registrations are
    added and withdrawn continuously and a party found at checkout may
    no longer be routable days later (and vice versa).

    Treat the early result as advisory, resolve again at generation,
    and store the resolved electronic address on the transaction —
    the routing address isn't always the bare SIREN. See
    [Directory lookup](/guides/fr-lookup).
  </Accordion>

  <Accordion title="What should we do if the customer doesn't belong to the Peppol network?">
    In countries where Peppol is the standard but not mandatory, you may still need to issue an e-invoice when the recipient isn't on the network. Both parties can agree on an alternative transfer method, but the invoice must still be EN16931 compliant.

    Recommended approach:

    * Set up a separate workflow that generates the XML without the send-Peppol-document step
    * Or reuse your existing workflow without the customer Peppol ID — the send step is automatically skipped
    * Fetch the generated XML and deliver it through the agreed channel, typically email
  </Accordion>

  <Accordion title="How do I handle B2C invoices in Peppol?">
    B2C invoices typically lack the structured customer information required for Peppol delivery, and most consumers don't have inboxes. Use a conditional workflow:

    1. Add an **If/Else** step that checks for a customer inbox using `count(customer.inboxes, true) > 0`.
    2. On the `false` branch, generate a PDF and email it to the customer, then stop the flow.

    This routes B2B invoices through Peppol while keeping a smooth path for consumers.
  </Accordion>

  <Accordion title="How do I handle 'Receiver Not Found' errors?">
    If a job fails with `KO` and `receiver not found in the peppol network`, treat it like an invalid email address — the recipient simply isn't reachable on Peppol. Add the **Lookup Participant ID** step (ideally in a separate validation workflow run against customer data) so you catch missing IDs before generating the invoice.
  </Accordion>

  <Accordion title="Should I set the `$regime` field when using Peppol?">
    No. The regime is automatically derived from the supplier's settings, which is the recommended approach for Peppol — leave it unset on the document.
  </Accordion>

  <Accordion title="Where do I find Peppol GOBL documentation?">
    See the [`eu-en16931-v2017`](https://docs.gobl.org/addons/eu-en16931-v2017) addon for the field and validation rules Peppol BIS Billing 3.0 builds on, and the [Peppol app reference](/apps/peppol) for supported document types and Participant ID schemes.
  </Accordion>
</AccordionGroup>

More available in our [France FAQ](/faq/france) section

***

<Card title="Participate in our community" icon="forumbee" href="https://community.invopop.com" arrow="true" horizontal>
  Ask and answer questions about your Chargebee integration →
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.