Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/PDNMX/s1_backend/llms.txt

Use this file to discover all available pages before exploring further.

S1 Backend has two configuration surfaces that must be set up before the server can handle live provider traffic. The first is a minimal .env file that controls the HTTP port the server binds to. The second — and more important — is endpoints.json, a JSON file at the project root that acts as the provider registry: every federated government data supplier the gateway should query is declared here, along with its OAuth 2.0 credentials and API endpoint URLs. Both files are excluded from version control and must be created locally from the provided .example templates.

Environment Variables

S1 Backend uses dotenv to load environment configuration from a .env file located at the project root. The file is read by bin/www at startup before the HTTP server is created.
PORT
number
default:"3000"
The TCP port the HTTP server listens on. The .env.example file recommends 3101 for local development. If this variable is absent or not set, the server falls back to port 3000.
Example .env file:
.env
PORT=3101
To create it from the template:
cp .env.example .env
When deploying behind a reverse proxy (nginx, Traefik, etc.) you can set PORT to any internal port and expose a different public port at the proxy layer.

endpoints.json

endpoints.json is a required JSON file at the project root. It is loaded synchronously via require('../endpoints') when the Express router initialises, which means the application will throw a module-not-found error at startup if the file does not exist. The file contains a JSON array where each element describes one federated data provider. To create it from the template:
cp endpoints.json.example endpoints.json
Full structure (from endpoints.json.example):
endpoints.json
[
  {
    "supplier_id": "EDOMEX",
    "supplier_name": "Secretaría Ejecutiva del Sistema Estatal Anticorrupción del Estado México",
    "system_id": 1,
    "type": "REST",
    "levels": [
      "estatal"
    ],
    "url": "",
    "entities_url": "",
    "token_url": "",
    "username": "",
    "password": "",
    "client_id": "",
    "client_secret": ""
  }
]
endpoints.json contains sensitive OAuth 2.0 credentials (usernames, passwords, client secrets). This file is listed in .gitignore and must never be committed to version control or included in container images. Use secrets management tooling (environment-specific secret stores, Docker secrets, etc.) for production deployments.

Field Reference

supplier_id
string
required
Unique identifier for this provider. Used internally to match provider entries and is exposed in API responses as supplier_id. It is also the value clients send in the supplier_id body field of POST /v1/search to target a specific provider. Example: "EDOMEX".
supplier_name
string
required
Human-readable full name of the provider institution. Returned in all API responses alongside supplier_id so consumers can display a meaningful label. Example: "Secretaría Ejecutiva del Sistema Estatal Anticorrupción del Estado México".
system_id
number
required
Numeric identifier for the PDN system this provider belongs to. Always 1 for Sistema 1 (asset declarations).
type
string
required
Protocol type of the provider’s API. Currently always "REST". This field is echoed back in data responses as endpoint_type.
levels
array of strings
required
One or more government levels that this provider covers. Valid values are:
  • "federal" — Federal-level institutions.
  • "estatal" — State-level institutions.
  • "municipal" — Municipal-level institutions.
This array is used by POST /v1/summary to filter which providers respond to a given nivel_gobierno value. A provider is included in a query if its levels array contains the requested level.
url
string
required
The provider’s data API endpoint URL. The gateway sends POST requests to this URL with the query options in the JSON body and a Bearer token in the Authorization header to retrieve asset declaration records.
entities_url
string
URL for fetching the list of entities or institutions from the provider. Used by the fetchEntities() function in routes/rest_data.js. This field is optional; leave it empty if the provider does not expose an entities endpoint.
token_url
string
required
The OAuth 2.0 token endpoint URL for this provider. The gateway posts a password-grant request to this URL before every data query to obtain a short-lived access_token.
username
string
required
The resource owner username sent in the OAuth 2.0 password-grant request (grant_type=password).
password
string
required
The resource owner password sent in the OAuth 2.0 password-grant request.
client_id
string
required
The OAuth 2.0 client ID. Sent both in the token request body (client_id field) and as the username in the HTTP Basic Authorization header of the token request.
client_secret
string
required
The OAuth 2.0 client secret. Sent both in the token request body (client_secret field) and as the password in the HTTP Basic Authorization header of the token request.

OAuth 2.0 Authentication Flow

S1 Backend authenticates with each provider using the OAuth 2.0 Resource Owner Password Credentials grant (password grant). The getToken() function in routes/rest_data.js is called on every data request — there is no token caching between requests. The token request is a POST to the provider’s token_url with:
  • Body (URL-encoded via qs.stringify):
    grant_type=password
    username=<username>
    password=<password>
    client_id=<client_id>
    client_secret=<client_secret>
    
  • Authorization header: HTTP Basic authentication with client_id as the username and client_secret as the password.
On a successful response the gateway extracts access_token from the JSON body and attaches it as a Bearer token to the subsequent POST request sent to the provider’s url.
getToken(endpoint)

  ├─ POST {token_url}
  │    Authorization: Basic base64(client_id:client_secret)
  │    Body: grant_type=password&username=…&password=…&client_id=…&client_secret=…

  └─ { access_token: "eyJ…" }

        └─ POST {url}
             Authorization: Bearer eyJ…
             Content-Type: application/json;charset=UTF-8
             Body: { page, pageSize, query, sort }
If getToken() fails (network error, invalid credentials, etc.), the error is logged via log4js and the provider’s slot in the aggregated response is populated with an error object rather than results — ensuring other providers still contribute their data.
The axios instance used by S1 Backend is configured with rejectUnauthorized: false, meaning it accepts self-signed TLS certificates from provider APIs. This is intentional for compatibility with government infrastructure but should be reviewed for hardened production deployments.

Multiple Providers

To register additional providers, append more objects to the JSON array in endpoints.json. Each entry is completely independent — the gateway queries all matching providers in parallel using Promise.all():
endpoints.json
[
  {
    "supplier_id": "EDOMEX",
    "supplier_name": "Secretaría Ejecutiva del Sistema Estatal Anticorrupción del Estado México",
    "system_id": 1,
    "type": "REST",
    "levels": ["estatal"],
    "url": "https://edomex.example.gov.mx/api/s1/declaraciones",
    "entities_url": "https://edomex.example.gov.mx/api/s1/entidades",
    "token_url": "https://edomex.example.gov.mx/oauth/token",
    "username": "api_user",
    "password": "secret",
    "client_id": "client_abc",
    "client_secret": "client_secret_xyz"
  },
  {
    "supplier_id": "FEDERAL_SFP",
    "supplier_name": "Secretaría de la Función Pública",
    "system_id": 1,
    "type": "REST",
    "levels": ["federal"],
    "url": "https://sfp.example.gob.mx/api/s1/declaraciones",
    "entities_url": "",
    "token_url": "https://sfp.example.gob.mx/oauth/token",
    "username": "api_user",
    "password": "secret",
    "client_id": "client_def",
    "client_secret": "client_secret_uvw"
  }
]
The levels array on each provider determines which queries it participates in:
  • A POST /v1/summary with nivel_gobierno: "estatal" fans out only to providers whose levels array includes "estatal".
  • A POST /v1/summary with nivel_gobierno: "federal" fans out only to providers with "federal" in levels.
  • A POST /v1/summary with no nivel_gobierno or institucion filter fans out to all registered providers.
  • A POST /v1/search always targets exactly one provider, identified by the supplier_id field in the request body.

Build docs developers (and LLMs) love