{"id":48461849,"url":"https://github.com/phax/phorm","last_synced_at":"2026-04-10T13:01:19.106Z","repository":{"id":345303000,"uuid":"490424737","full_name":"phax/phorm","owner":"phax","description":"Phorm - Business Document Validation Service","archived":false,"fork":false,"pushed_at":"2026-04-02T14:41:53.000Z","size":411,"stargazers_count":12,"open_issues_count":2,"forks_count":3,"subscribers_count":9,"default_branch":"main","last_synced_at":"2026-04-07T02:25:59.540Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-05-09T19:52:25.000Z","updated_at":"2026-04-02T15:36:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/phax/phorm","commit_stats":null,"previous_names":["phax/phorm"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/phax/phorm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phax%2Fphorm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phax%2Fphorm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phax%2Fphorm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phax%2Fphorm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phax","download_url":"https://codeload.github.com/phax/phorm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phax%2Fphorm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31643431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-07T02:08:15.009Z","updated_at":"2026-04-10T13:01:19.093Z","avatar_url":"https://github.com/phax.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Phorm\n\n\u003c!-- ph-badge-start --\u003e\n[![Sonatype Central](https://maven-badges.sml.io/sonatype-central/com.helger/phorm/badge.svg)](https://maven-badges.sml.io/sonatype-central/com.helger/phorm/)\n[![javadoc](https://javadoc.io/badge2/com.helger/phorm/javadoc.svg)](https://javadoc.io/doc/com.helger/phorm)\n\u003c!-- ph-badge-end --\u003e\n\nThis repository contains a simple, standalone validation service (Phorm) accessible by API only.\n\nThe implementation of the validation is based on the open source validation engine [phive](https://github.com/phax/phive) and the collection of rules [phive-rules](https://github.com/phax/phive-rules).\n\n\"Phorm\" is a combination of \"PH + form + conform\" and is all about standards, compliance, and correctness.\n\n# Development environment\n\n* Requires Java 17 or newer - Java 21 or later is recommended\n* [Apache Maven](https://maven.apache.org) is used as the build tool. May be abstracted by a Docker image.\n* Coding language: English\n\n# API\n\nThe services offers the following APIs.\n\n* POST **`/api/validate/{vesid}`**\n  * Validate the provided payload in the body against the validation rules, identified by `{vesid}`\n  * Requires the HTTP header `X-Token` to have the configured value (see below for `phorm.api.requiredtoken`)\n  * If the HTTP Request Header `Accept` with value `application/xml`  is present, the result is an XML structure. Else the result is a JSON structure\n  * Test invocation (replace `XXX` with real token):\n    * `curl -X POST -H \"Content-Type: application/xml\" -H \"X-Token: XXX\" -d @src/test/resources/testfiles/peppol-bis3/base-example.xml http://localhost:8080/api/validate/eu.peppol.bis3:invoice:latest`\n* GET **`/api/get/vesids`**\n  * Get a list of all registered VESIDs\n  * The optional URL parameter `include-deprecated` can be used to also return registered, but deprecated VES IDs. No parameter value is needed\n  * The result is a JSON structure\n    * `curl -X GET http://localhost:8080/api/get/vesids`\n* POST **`/api/determinedoctype`**\n  * Try to detect the format and payload specifics of a document instance.\n  * The document instance must be the POST payload.\n  * Requires the HTTP header `X-Token` to have the configured value (see below for `phorm.api.requiredtoken`)\n  * The result is a JSON structure\n  * Test invocation (replace `XXX` with real token):\n    * `curl -X POST -H \"Content-Type: application/xml\" -H \"X-Token: XXX\" -d @src/test/resources/testfiles/peppol-bis3/base-example.xml http://localhost:8080/api/determinedoctype`\n  * Example output:\n```json\n{\n  \"syntaxID\":\"ubl2-invoice\",\n  \"syntaxVersion\":\"2.1\",\n  \"sender\":\"iso6523-actorid-upis::0088:9482348239847239874\",\n  \"receiver\":\"iso6523-actorid-upis::0002:FR23342\",\n  \"doctype\":\"busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1\",\n  \"process\":\"cenbii-procid-ubl::urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\",\n  \"customizationID\":\"urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\",\n  \"bdid\":\"Snippet1\",\n  \"senderName\":\"SupplierTradingName Ltd.\",\n  \"senderCountryCode\":\"GB\",\n  \"receiverName\":\"BuyerTradingName AS\",\n  \"receiverCountryCode\":\"SE\",\n  \"vesid\":\"eu.peppol.bis3:invoice:latest-active\",\n  \"profileName\":\"Peppol BIS Billing UBL Invoice V3\"\n}\n```\n* POST **`/api/dd_and_validate`**\n  * Determine the document type and afterwards validate the provided payload in the body against the determined validation rules\n  * Requires the HTTP header `X-Token` to have the configured value (see below for `phorm.api.requiredtoken`)\n  * If the HTTP Request Header `Accept` with value `application/xml` is present, the result is an XML structure.\n    If the HTTP Request Header `Accept` with value `text/html` is present, the result is an HTML file.\n    Else the result is a JSON structure\n  * Test invocation (replace `XXX` with real token):\n    * `curl -X POST -H \"Content-Type: application/xml\" -H \"X-Token: XXX\" -d @src/test/resources/testfiles/peppol-bis3/base-example.xml http://localhost:8080/api/dd_and_validate/`\n\n# Configuration\n\nPhorm comes with one configuration file called `application.properties`.\nThe lookup rules for the file is defined in https://github.com/phax/ph-commons/wiki/ph-config\n\nIt supports the following settings:\n* **`global.debug`**: overall debug mode. This enables additional checks that should not be executed every time (e.g. because they are slow or because they are spamming the logfile etc.). This flag has no impact on the logging level! This flag should be set to `true` in development mode, but to `false` in production mode. The value of this field is internally maintained in class `com.helger.commons.debug.GlobalDebug`.\n* **`global.production`**: overall production mode. If this flag is set to `false` certain functionality not applicable in development environment (like mass mail sending) is disabled. This flag should be set to `true` in production mode.\n* **`webapp.datapath`**: the path where all relevant data and settings are stored. This can e.g. be a relative path (like `conf` - relative to the web application directory) for development purposes but should be an absolute path (e.g. `/config/phorm`) in production. Make sure the user running Phorm has write access to this folder.\n* **`webapp.checkfileaccess`**: a flag that determines whether the directory of the web application should be checked for read and write access. This is only required if the data path inside the web application and should therefore always be `false`.\n* **`webapp.testversion`**: a special indicator for the web application whether the version should be highlighted as a \"test\" version. Set to `true` in debug mode and `false` in production mode.\n* **`phorm.statusapi.enabled`**: a flag that indicates, if the status API (`/status`) should deliver data or not.\n* **`phorm.api.requiredtoken`**: the specific value of the `X-Token` header that must be provided to access the API. Customize this once and don't share it. The development default is `phorm-dev-token`.\n* **`phorm.api.response.onfailure.http400`**: a flag to indicate, whether the API should return HTTP 400 (Bad Request) on failed validations or not. The default is `true` for backwards compatibility reasons.\n* **`phorm.api.response.log.payload`**: a flag to indicate, whether the validation response should be logged in the console or not. The default is `false`.\n\n# Building\n\n## From Source\n\n* Requires Java 17 or higher\n* Build with Apache Maven 3.x - via `mvn clean install`\n\n* Alternatively build with a Docker Maven image:\n\n```\nbuild-with-docker.cmd clean install\n```\nor\n```\n./build-with-docker.sh clean install\n```\n\n## Docker image\n\nBuilding:\n\n```shell\ndocker build --pull -t phelger/phorm .\n```\n\nThe old image tag `phelger/valsvc` is also maintained for backwards compatibility:\n```shell\ndocker tag phelger/phorm phelger/valsvc\n```\n\nRunning:\n\n```shell\ndocker run -d --name phorm -p 8080:8080 phelger/phorm\n```\n\nExample curl command (use the correct \"X-Token\" and the right address):\n```\ncurl -d \"@base-example.xml\" -H \"Content-Type: application/xml\" -H \"X-Token: XXX\" -X POST http://localhost:8080/api/validate/eu.peppol.bis3:invoice:latest\n```\n\n## Standard Docker images\n\nPre-built Docker images are available on Docker Hub:\n\n* `phelger/phorm` — for **linux/amd64**\n* `phelger/phorm-arm64` — for **linux/arm64**\n\nBoth images are tagged with the specific version (e.g. `2.0.0`) as well as `latest`.\n\nThe multi-architecture build script is located in `docker/build-all.sh`.\n\n# Phorm Updates\n\nIf an update is made to the validation, you have to do a `git pull` and recompile.\n\nTo make sure your own configuration is kept unchanged, my suggestion is to create a file `private-application.properties`\n  in the `src/main/resources` folder of your checked-out copy (same folder as `application.properties`),\n  where you can adjust or change all the configuration entries that are important to you.\n\nThe file with this specific name and within this folder has a higher priority than the default\n  `application.properties` file and is also marked as \"ignored\" in git, i.e. changes to this file\n  are not overwritten during updates from the repository.\nIf the file is in the correct folder, it will also be included in the compilation process and\n  is therefore available out of the box for Phorm.\n\nAs an alternative to using `private-application.properties` you may also consider using\n   environment variables or Java system properties for the configuration -\n   see https://github.com/phax/ph-commons/wiki/ph-config for details.\n\n# News and noteworthy\n\nv2.0.2 - 2026-04-02\n* Updated to phive 12.0.2 and phive-rules 4.3.0\n\nv2.0.1 - 2026-03-25\n* Updated to phive-rules 4.2.5\n\nv2.0.0 - 2026-03-18\n* Made the repository public - thanks for all the supporters!!!\n* Starting to use semantic versioning\n\n2026-03-17\n* Updated to phive 12.0.1 and phive-rules 4.2.3\n\n2026-03-12\n* **Rebranding**: the project has been renamed from \"Validation Service\" / \"valsvc\" to **Phorm**\n* The Maven artifact ID changed from `validation-service` to `phorm`, so the WAR file is now `phorm.war` instead of `validation-service.war`\n* The Java package was renamed from `com.helger.valsvc` to `com.helger.phorm`\n* The Docker image is now `phelger/phorm` (the old tag `phelger/valsvc` is still provided for backwards compatibility)\n* Configuration property keys were renamed from `valsvc.*` to `phorm.*` (e.g. `valsvc.api.requiredtoken` → `phorm.api.requiredtoken`). The old `valsvc.*` keys are still accepted as fallback values.\n* The log prefix changed from `[VAL-SVC]` to `[PHORM]`\n* The default Docker data path changed from `/config/valsvc` to `/config/phorm`\n\n2026-02-22\n* Updated to phive 12.0.0 and phive-rules 4.2.0\n* Both `/api/validate/` and `/api/dd_and_validate` are now able to create HTML results (first draft)\n\n2026-02-18\n* Updated to phive-rules 4.1.8\n\n2025-09-02\n* The API `/api/determinedoctype` can now also return XML payload\n* Fixed an error with the document type ID scheme for PINT document types in determination\n\n2025-08-29\n* The minimum requirement is now Java 17\n\n2025-03-23\n* Added new API `/api/dd_and_validate` to run document type detection and validation in one call\n* Changed the default value of `phorm.api.response.log.payload` (formerly `valsvc.api.response.log.payload`) to `false`\n\n2025-03-10\n* Added the new phive-rules-zatca for Saudi Arabian invoice\n\n2025-03-08\n* Added all other remaining validation rules from phive-rules\n\n2025-03-04\n* Added Danish OIOUBL rules to the ruleset\n\n2025-01-09\n* The API `/api/validate/{vesid}` can return JSON or XML (depending on the `Accept` header)\n\n2024-12-06\n* Added new API `/api/determinedoctype` to auto detect payload details\n\n2024-12-05\n* the new configuration property `phorm.api.response.log.payload` (formerly `valsvc.api.response.log.payload`) can be used to disable logging of the result JSON\n* Added support for German ZuGFERD XML invoices \n\n2024-12-03\n* the new configuration property `phorm.api.response.onfailure.http400` (formerly `valsvc.api.response.onfailure.http400`) can be used to disable returning HTTP 400 on validation failure\n\n2024-09-17\n* updated to phive v10 and ph-diver v3\n\n2024-05-23\n* added UBL.BE rules as well \n\n2024-01-10\n* added XRechnung rules as well\n\n---\n\nMy personal [Coding Styleguide](https://github.com/phax/meta/blob/master/CodingStyleguide.md) |\nIt is appreciated if you star the GitHub project if you like it.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphax%2Fphorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphax%2Fphorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphax%2Fphorm/lists"}