Gratias
Fiscal Classification API
Classify a monthly compensation situation against per-country tax rules. The engine evaluates only the inputs you send: it never reads establishment or individual data, and it exposes no amounts from the platform. Results are informational and are not tax advice.
Authentication
Every request must carry an API key in the Authorization header using the Bearer scheme. Keys are issued from the Gratias back-office and shown only once at creation. A key must hold the fiscal:classify scope to call the classification endpoint.
Authorization: Bearer grt_live_xxxxxxxxxxxx.xxxxxxxxxxxxxxxxEach authenticated call counts against the key's daily quota. Once the quota is reached, further calls return 429 until the next UTC day.
POST /api/public/fiscal/classify
Send the situation to classify as a JSON body. All fields are inputs you provide; none are read from Gratias data.
Request body
| Field | Type | Description |
|---|---|---|
country | string | Establishment jurisdiction. One of: FR, ES, US, GB, IT, GR. |
year | integer | Calendar year (2000-2100). |
month | integer | Calendar month (1-12). |
monthlyBaseCents | integer | Monthly base compensation in integer cents, excluding gratuities. A value you provide. |
tipsCents | integer | Gratuities for the month in integer cents. A value you provide. |
Example request
curl -X POST https://your-domain.example/api/public/fiscal/classify \
-H "Authorization: Bearer grt_live_xxxxxxxxxxxx.xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"country": "FR",
"year": 2027,
"month": 3,
"monthlyBaseCents": 200000,
"tipsCents": 40000
}'Response
| Field | Type | Description |
|---|---|---|
statusKind | string | Regime nature: exempt, standard, reduced, deductible or self_assessment. |
ruleCode | string | null | Stable identifier of the matched rule. |
legalRef | string | null | Legal reference for the matched rule. |
disclaimer | string | Informational notice returned with every result. |
Example response
{
"statusKind": "exempt",
"ruleCode": "FR_EXO_2026_S2",
"legalRef": "LF 2026 art. 5; revalorisation SMIC 1er juin 2026",
"disclaimer": "This classification is derived solely from the inputs you provided. It is not tax advice and does not read any establishment or individual data. Confirm with a qualified local tax professional before relying on it."
}Error codes
Errors return a JSON body with an error message and a stable code. Validation errors (400) also include an issues array describing the offending fields. No internal detail is ever disclosed.
| Status | Code | Meaning |
|---|---|---|
400 | invalid_request | The request body failed validation (see issues). |
401 | invalid_key | Missing, invalid, inactive or revoked API key. |
403 | insufficient_scope | The key lacks the "fiscal:classify" scope. |
429 | rate_limited | Daily request quota exceeded (see Retry-After). |
500 | internal_error | Unexpected server error. |
Gratitude Kit (embedded thank-you journey)
The Gratitude Kit lets a chain application embed a house's thank-you journey directly inside its own experience (an overlay or an iframe). The guest chooses an amount and pays without leaving the host app.
The payment is always a direct debit from the guest to the employee's wallet through the Gratias PSP. The host application never touches the funds and never receives any individual data: no amount, no employee, no balance.
Requirements
- An API key holding the
embed:tipscope. - Each embedding origin (for example
https://app.your-chain.example) registered in the key's allowlist. Origins are managed in the Gratias back-office, per key.
GET /api/public/embed/context
Called from your backend to discover the embedding configuration for your key. Authenticate with the key in the Authorization header (Bearer scheme) and pass the embedding origin in the Origin header (or an ?origin= query parameter). The response carries only technical embedding facts.
curl "https://your-domain.example/api/public/embed/context" \
-H "Authorization: Bearer grt_live_xxxxxxxxxxxx.xxxxxxxxxxxxxxxx" \
-H "Origin: https://app.your-chain.example"Response
| Field | Type | Description |
|---|---|---|
allowedOrigin | string | The normalized host-app origin that is allowed to embed (the caller origin). |
appUrl | string | Public base URL of the Gratias app that serves the thank-you journey. |
tipPathTemplate | string | Path template of the journey to frame, with a {token} placeholder. |
frameAncestorsHint | string | Suggested value for your own frame-ancestors / CSP configuration. |
notice | string | Reminder that the payment is a direct guest-to-employee debit; the host app never touches funds. |
Error codes
| Status | Code | Meaning |
|---|---|---|
400 | invalid_request | Missing or invalid embedding origin (Origin header or ?origin=). |
401 | invalid_key | Missing, invalid, inactive or revoked API key. |
403 | insufficient_scope | The key lacks the "embed:tip" scope. |
403 | origin_not_allowed | The origin is not in this key's allowlist. |
429 | rate_limited | Daily request quota exceeded (see Retry-After). |
500 | internal_error | Unexpected server error. |
Integration snippet
Paste the following web component in your host app. It defines a <tacitapay-thankyou> element that mounts the journey in an iframe on the Gratias origin, so the settlement happens on our PSP. Never paste your key secret: the snippet only references the key prefix.
<!-- Gratias: parcours de remerciement embarque. Cle: grt_live_xxxxxxxxxxxx -->
<!-- D49: le paiement est un debit DIRECT du client vers le wallet du salarie via -->
<!-- notre PSP. Cette app ne touche jamais les fonds. Ne collez jamais votre secret ici. -->
<script>
(function () {
if (customElements.get("tacitapay-thankyou")) return;
var BASE = "https://gratias.io";
customElements.define(
"tacitapay-thankyou",
class extends HTMLElement {
connectedCallback() {
var token = this.getAttribute("token") || "";
var frame = document.createElement("iframe");
frame.src = BASE + "/embed/" + encodeURIComponent(token);
frame.setAttribute("title", "Gratias");
frame.setAttribute("allow", "payment " + BASE);
frame.setAttribute("loading", "lazy");
frame.style.border = "0";
frame.style.width = "100%";
frame.style.height = this.getAttribute("height") || "720px";
this.replaceChildren(frame);
}
}
);
})();
</script>
<!-- Usage: <tacitapay-thankyou token="LE_JETON_DU_SALARIE"></tacitapay-thankyou> -->Usage: <tacitapay-thankyou token="THE_EMPLOYEE_TOKEN"></tacitapay-thankyou>. Only origins present in the key's allowlist are allowed to embed the journey; any other origin is refused.
OpenAPI specification
A machine-readable OpenAPI 3.0 document is served at /api/public/fiscal/openapi.json. It describes only caller-provided inputs and technical outputs, with no individual amounts from the platform.