Module: Einvoicing::Connect::FR::Directory
- Defined in:
- lib/einvoicing/connect/fr/directory.rb
Overview
Consultation of the central French e-invoicing directory (the PPF directory operated by DGFiP/AIFE).
Given a French SIREN or SIRET, resolves the recipient's e-invoicing routing information: the registered reception platform (PDP) and its technical routing code. This is the lookup an issuing platform performs to know where to deliver an invoice for a company.
NOTE: The official DGFiP/AIFE directory API specification is not yet
final. The reform pilot opened on 2026-02-27, with general availability
on 2026-09-01. The endpoint and response shape below follow the published
interoperability framework and are expected to evolve — point
Directory.api_url= at the production endpoint once it is confirmed.
Constant Summary collapse
- DEFAULT_API_URL =
Placeholder endpoint, overridable via Directory.api_url= or per call.
"https://annuaire.facturation.gouv.fr/api/v1/destinataires"
Class Attribute Summary collapse
Class Method Summary collapse
-
.lookup(identifier, api_url: self.api_url) ⇒ Object
Look up the routing information for a recipient identified by SIREN (9 digits) or SIRET (14 digits).
-
.route(party, api_url: self.api_url) ⇒ Object
Resolve the routing information for a Party, preferring its SIRET and falling back to its SIREN.
Class Attribute Details
.api_url ⇒ Object
30 31 32 |
# File 'lib/einvoicing/connect/fr/directory.rb', line 30 def api_url @api_url ||= DEFAULT_API_URL end |
Class Method Details
.lookup(identifier, api_url: self.api_url) ⇒ Object
Look up the routing information for a recipient identified by SIREN (9 digits) or SIRET (14 digits).
Returns a Hash on success, or nil on any error / no match:
{
identifier: "55203253400017",
level: "SIRET", # or "SIREN"
routing_code: "PDP000123", # technical routing code
platform_id: "0000000000000", # PDP registration id
platform_name: "Acme PDP",
status: "active"
}
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/einvoicing/connect/fr/directory.rb', line 47 def self.lookup(identifier, api_url: self.api_url) id = identifier.to_s.gsub(/\s/, "") return nil unless id.match?(/\A\d{9}(\d{5})?\z/) uri = URI(api_url) uri.query = URI.encode_www_form(identifiant: id) response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https", open_timeout: 5, read_timeout: 10) do |http| http.get(uri.request_uri) end return nil unless response.code == "200" parse(JSON.parse(response.body)) rescue StandardError nil end |
.route(party, api_url: self.api_url) ⇒ Object
Resolve the routing information for a Party, preferring its SIRET and falling back to its SIREN. Returns the routing Hash or nil.
68 69 70 71 72 73 74 |
# File 'lib/einvoicing/connect/fr/directory.rb', line 68 def self.route(party, api_url: self.api_url) identifier = party.siret.to_s.strip identifier = party.siren.to_s.strip if identifier.empty? && party.respond_to?(:siren) return nil if identifier.empty? lookup(identifier, api_url: api_url) end |