Skip to content
PPAI-ETMSDeveloper Portal

API reference

The machine API lives under /api/v1 on your assigned API base URL. Every response uses the same envelope regardless of endpoint: { success, data, error }.

Machine endpoints (/api/v1)

All endpoints below require Authorization: Bearer … plus the HMAC signature headers, except /oauth/token, /openapi.json and /docs. See the integration guide for the exact signing algorithm.

MethodPathScopeNotes
POST/oauth/tokenExchange client_id/client_secret for a 15-minute bearer token.
POST/ppai/policiesppai:transmitTransmit a new PPAI certificate (one or more vehicles).
GET/ppai/policies/search?plateNumber&mvFileNumber&chassisNumber&engineNumber&policyNumber&cocNumber&status&pageppai:readSearch registered records visible to your organization.
GET/ppai/policies/{ltfrbReference}ppai:readFetch one record by its LTFRB reference.
POST/ppai/policies/{ltfrbReference}/amendmentsppai:amendAmend mutable fields; creates a new version.
POST/ppai/policies/{ltfrbReference}/cancellationppai:cancelCancel a certificate (lifecycle only; nothing is deleted).
GET/ppai/transmissions/{transmissionReferenceOrExternalId}ppai:readLook up a transmission's acknowledgment by either reference.
GET/ppai/vehicles/{identifier}/coveragevehicles:verifyCoverage check by any of the four identifiers — no operator PII returned.
GET/openapi.jsonpublicMachine-readable OpenAPI 3 document.
GET/docspublicInteractive Scalar API reference.

Example: successful transmission

A POST /api/v1/ppai/policies that passes L1-L4 validation with no flags returns ACCEPTED (PRD §26 acknowledgment fields live inside data). There is no insurer portal to generate a PDF, so acknowledgmentUrl is always null — the JSON acknowledgment itself is the record of registration:

json
HTTP/1.1 201 Created
Content-Type: application/json

{
  "success": true,
  "data": {
    "status": "ACCEPTED",
    "transmissionReference": "PPAI-TX-2026-0000012345",
    "transactionReference": "LTFRB-PPAI-2026-000012345",
    "ltfrbReference": "LTFRB-PPAI-2026-000012345",
    "externalTransactionId": "INSUR-20260917-000123",
    "kind": "CREATE",
    "policyNumber": "POL-2026-00981",
    "certificateOfCover": "COC-2026-00981",
    "plateNumber": "NGP1234",
    "plateNumbers": ["NGP1234"],
    "coverageStatus": "ACTIVE",
    "version": 1,
    "receivedAt": "2026-09-17T02:14:31.000Z",
    "replayed": false,
    "warnings": [],
    "errors": [],
    "flags": [],
    "referenceMatches": [{ "plateNumber": "NGP1234", "result": "MATCHED" }],
    "acknowledgmentUrl": null,
    "disclaimer": "ACCEPTED means the PPAI record was accepted as an electronic transmission to LTFRB. It does not constitute an LTFRB guarantee of the legal validity of the underlying insurance policy."
  },
  "error": null
}

Example: rejected transmission

Any Level 1-3 error rejects the whole transmission — nothing is written to the registry. error.details[] lists every finding, not just the first one, so an integrator can fix everything in one pass. See status codes & errors for the full code list.

json
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "success": false,
  "data": null,
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Transmission failed validation.",
    "details": [
      { "field": "vehicles[0].chassisNumber", "code": "REQUIRED", "level": 1, "message": "Chassis number is required." },
      { "field": "certificate.expirationDate", "code": "INVALID_DATE_RANGE", "level": 2, "message": "Expiration date must be after the effective date." }
    ],
    "requestId": "5b6a5b2e-6e0a-4e2a-9a7b-2b6a5b2e6e0a"
  }
}

The session-based admin API

/admin/v1/* (LTFRB Admin — the only human-login realm; there is no insurer portal or insurer session realm) uses cookie sessions with CSRF protection instead of OAuth2/HMAC. It is documented for engineering reference in the spec, not intended for third-party integration — including the endpoints LTFRB staff use to issue, rotate and revoke your API credentials (POST /admin/v1/api-clients and friends). Insurers should use /api/v1 exclusively; see sandbox onboarding for how to actually get credentials.