{
  "info": {
    "_postman_id": "vigilant-api-collection-v1",
    "name": "Vigilant API — TrackJud",
    "description": "Official Postman collection for the Vigilant API by TrackJud.\n\n**Vigilant** is a Brazilian court data API that lets you query lawsuits across 12 judicial sources (ESAJ, PJe, EPROC, and others) covering 10 Brazilian states with a single REST call.\n\n## Quick start\n\n1. Sign up at https://vigilant.trackjud.com.br/users/log-in (5 free credits)\n2. Generate an API key in your dashboard\n3. Set the `apiKey` collection variable below\n4. Run **Create Consult** with a CPF and a list of court codes\n5. Poll **Get Consult** until status is `done`, then read the structured results\n\n## Authentication\n\nAll endpoints under `/api/v1/*` require a Bearer token (your API key) in the `Authorization` header. The collection sets this automatically via the `apiKey` variable.\n\n## Pricing\n\n- R$ 0,10 per court queried per CPF\n- 5 free credits on signup, no credit card required\n- Repeat queries within 2 days are served from cache at no extra cost\n\n## Documentation\n\n- Interactive API docs (Scalar UI): https://vigilant.trackjud.com.br/api/docs\n- OpenAPI 3.1 spec: https://vigilant.trackjud.com.br/api/openapi\n- Health check: https://vigilant.trackjud.com.br/api/health\n\n## Errors\n\nAll error responses follow [RFC 7807 Problem Details](https://www.rfc-editor.org/rfc/rfc7807) with `Content-Type: application/problem+json`.\n\n## Support\n\n- Email: support@trackjud.com.br\n- Marketing site: https://trackjud.com.br/developers/\n",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://vigilant.trackjud.com.br",
      "type": "string",
      "description": "Base URL of the Vigilant API. Production only — there is no separate sandbox; the 5 free credits on signup serve as your sandbox."
    },
    {
      "key": "apiKey",
      "value": "REPLACE_WITH_YOUR_API_KEY",
      "type": "string",
      "description": "Your Vigilant API key. Generate one in the dashboard at https://vigilant.trackjud.com.br after signing up."
    },
    {
      "key": "consultId",
      "value": "",
      "type": "string",
      "description": "Set automatically by the Create Consult request via test script. Used by Get/Cancel/Reprocess Consult requests."
    }
  ],
  "item": [
    {
      "name": "Health Check",
      "request": {
        "method": "GET",
        "header": [],
        "auth": {
          "type": "noauth"
        },
        "url": {
          "raw": "{{baseUrl}}/api/health",
          "host": ["{{baseUrl}}"],
          "path": ["api", "health"]
        },
        "description": "Returns the application health status, version, and connectivity to all critical dependencies (database, queue) and external services (payment, solver, email).\n\n**No authentication required.**\n\n**Response 200**: `{ \"status\": \"healthy\", \"version\": \"x.y.z\", \"checks\": {...}, \"external_services\": {...} }`\n\n**Response 503**: `{ \"status\": \"degraded\", ... }` — at least one critical check failed.\n\nUse this for upstream monitoring (Pingdom, UptimeRobot, etc) or to verify the API is reachable from your network before troubleshooting auth issues."
      },
      "response": [
        {
          "name": "Healthy",
          "originalRequest": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/health",
              "host": ["{{baseUrl}}"],
              "path": ["api", "health"]
            }
          },
          "status": "OK",
          "code": 200,
          "header": [{ "key": "Content-Type", "value": "application/json" }],
          "body": "{\n  \"status\": \"healthy\",\n  \"version\": \"0.17.0\",\n  \"checks\": {\n    \"database\": \"ok\",\n    \"queue\": \"ok\"\n  },\n  \"external_services\": {\n    \"payment\": \"ok\",\n    \"solver\": \"ok\",\n    \"email\": \"ok\"\n  }\n}"
        }
      ]
    },
    {
      "name": "List Available Courts",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/courts",
          "host": ["{{baseUrl}}"],
          "path": ["api", "v1", "courts"]
        },
        "description": "Returns the registry of all court sources Vigilant can query, with their operational status (`active`, `unavailable`, or `coming_soon`).\n\nUse this to:\n- Discover which courts are available before creating a consult\n- Build a UI for users to pick courts\n- Validate court codes in your application\n\nOnly courts with status `active` should be passed in the `courts` array of the Create Consult endpoint. Courts with status `unavailable` may be accepted but will likely fail. Courts with status `coming_soon` are visible but not yet queryable.\n\n**Authentication**: Bearer token (API key) required."
      },
      "response": [
        {
          "name": "Success",
          "originalRequest": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/courts",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "courts"]
            }
          },
          "status": "OK",
          "code": 200,
          "header": [{ "key": "Content-Type", "value": "application/json" }],
          "body": "{\n  \"data\": [\n    {\n      \"court_code\": \"TJSP\",\n      \"system\": \"esaj\",\n      \"name\": \"Tribunal de Justiça de São Paulo\",\n      \"state\": \"SP\",\n      \"status\": \"active\"\n    },\n    {\n      \"court_code\": \"TJMG\",\n      \"system\": \"pje\",\n      \"name\": \"Tribunal de Justiça de Minas Gerais\",\n      \"state\": \"MG\",\n      \"status\": \"active\"\n    }\n  ]\n}"
        }
      ]
    },
    {
      "name": "Create Consult",
      "event": [
        {
          "listen": "test",
          "script": {
            "exec": [
              "// Auto-capture consult_id from response so subsequent",
              "// Get/Cancel/Reprocess requests can use it via {{consultId}}",
              "if (pm.response.code === 200 || pm.response.code === 202) {",
              "    const data = pm.response.json().data;",
              "    if (data && data.consult_id) {",
              "        pm.collectionVariables.set('consultId', data.consult_id);",
              "        console.log('Saved consultId:', data.consult_id);",
              "    }",
              "}"
            ],
            "type": "text/javascript"
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"document\": \"529.982.247-25\",\n  \"courts\": [\"TJSP\", \"TJMG\", \"TRF1\"],\n  \"force_refresh\": false\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/api/v1/consults",
          "host": ["{{baseUrl}}"],
          "path": ["api", "v1", "consults"]
        },
        "description": "Creates a consult — a search request for one CPF across one or more courts.\n\n**Request body**:\n- `document` (required): CPF in masked (`NNN.NNN.NNN-NN`) or unmasked (`NNNNNNNNNNN`) format. Validated with mod 11 algorithm.\n- `courts` (required): array of court codes (e.g., `[\"TJSP\", \"TJMG\"]`). Use the List Courts endpoint to discover available codes.\n- `force_refresh` (optional, default `false`): when `true`, bypasses the cache and triggers a fresh scrape. Costs 5x more (5 credits per court instead of 1).\n\n**Cache behavior** (the most important part to understand):\n- Fresh cache (< 2 days old): returns **200** with the data immediately, source `cache`. No new scraping triggered.\n- Stale cache (>= 2 days old): returns **200** with the data + `\"stale\": true` and triggers a background refresh.\n- No cache: returns **202** with a `consult_id` you can poll. Scraping starts immediately.\n\n**Always searches all instances (1st and 2nd) and all legal areas** — there is no filter for that.\n\n**Authentication**: Bearer token (API key) required.\n\n**Errors**:\n- `400` — Unknown court code, empty courts list, or court is not implemented\n- `401` — Missing or invalid API key\n- `402` — Insufficient credits\n- `422` — Invalid CPF (failed mod 11 check)"
      },
      "response": [
        {
          "name": "200 — Cache hit (fresh)",
          "originalRequest": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"document\": \"529.982.247-25\",\n  \"courts\": [\"TJSP\"]\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/consults",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "consults"]
            }
          },
          "status": "OK",
          "code": 200,
          "header": [{ "key": "Content-Type", "value": "application/json" }],
          "body": "{\n  \"data\": {\n    \"source\": \"cache\",\n    \"stale\": false,\n    \"consult_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n    \"document\": \"529.982.247-25\",\n    \"courts\": [\n      {\n        \"court\": \"TJSP\",\n        \"system\": \"esaj\",\n        \"source\": \"cache\",\n        \"stale\": false,\n        \"extracted_at\": \"2026-04-15T14:30:00Z\",\n        \"processes\": [\n          {\n            \"numero_processo_unico\": \"1234567-89.2024.8.26.0100\",\n            \"classe\": \"Procedimento Comum Cível\",\n            \"situacao\": \"Em andamento\",\n            \"distribuido_em\": \"15/01/2024\",\n            \"competencia\": \"1ª Vara Cível\",\n            \"valor_causa\": \"R$ 50.000,00\",\n            \"instance\": \"1\",\n            \"partes\": [\n              { \"tipo\": \"Autor\", \"nome\": \"João da Silva\", \"representante\": \"Dr. Advogado OAB/SP 12345\" }\n            ],\n            \"movimentos\": [\n              { \"data_movimento\": \"01/03/2024\", \"descricao\": \"Juntada de Petição\", \"movimento\": \"60\" }\n            ],\n            \"assuntos\": [\n              { \"cod_assunto\": 7619, \"ds_assunto\": \"Indenização por Dano Moral\" }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}"
        },
        {
          "name": "202 — New consult (no cache)",
          "originalRequest": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"document\": \"529.982.247-25\",\n  \"courts\": [\"TJSP\", \"TJMG\"],\n  \"force_refresh\": true\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/api/v1/consults",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "consults"]
            }
          },
          "status": "Accepted",
          "code": 202,
          "header": [{ "key": "Content-Type", "value": "application/json" }],
          "body": "{\n  \"data\": {\n    \"source\": \"processing\",\n    \"consult_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n    \"document\": \"529.982.247-25\",\n    \"courts\": [\n      { \"court\": \"TJSP\", \"system\": \"esaj\", \"status\": \"queued\" },\n      { \"court\": \"TJMG\", \"system\": \"pje\", \"status\": \"queued\" }\n    ]\n  }\n}"
        },
        {
          "name": "402 — Insufficient credits",
          "originalRequest": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/consults",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "consults"]
            }
          },
          "status": "Payment Required",
          "code": 402,
          "header": [{ "key": "Content-Type", "value": "application/problem+json" }],
          "body": "{\n  \"type\": \"https://vigilant.trackjud.com.br/errors/insufficient-credits\",\n  \"title\": \"Payment Required\",\n  \"status\": 402,\n  \"detail\": \"You need at least 3 credits to create this consult. Your balance is 1.\",\n  \"instance\": \"/api/v1/consults\"\n}"
        }
      ]
    },
    {
      "name": "Get Consult",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/consults/{{consultId}}",
          "host": ["{{baseUrl}}"],
          "path": ["api", "v1", "consults", "{{consultId}}"]
        },
        "description": "Retrieves the current status and results of a consult by its ID.\n\nUse this to **poll** for results after creating a consult that returned 202 (or 200 with `stale: true`). Polling interval recommendation: 2-5 seconds for typical consults; 60 seconds for batch monitoring.\n\n**Response**: same shape as Create Consult, with the `status` field on each court reflecting the current state:\n- `queued` — waiting in the worker queue\n- `running` — being scraped right now\n- `completed` — successfully extracted\n- `failed` — transient failure (will be retried automatically)\n- `unavailable` — court website is down or unreachable\n- `exhausted` — all retry attempts failed (terminal)\n- `canceled` — manually canceled\n\nThe top-level consult `status` becomes `done` when ALL court searches reach a terminal state (`completed`, `exhausted`, or `canceled`).\n\n**Authentication**: Bearer token (API key) required.\n\n**Errors**:\n- `404` — Consult not found, or not owned by your account."
      }
    },
    {
      "name": "Cancel Consult",
      "request": {
        "method": "PUT",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/consults/{{consultId}}/cancel",
          "host": ["{{baseUrl}}"],
          "path": ["api", "v1", "consults", "{{consultId}}", "cancel"]
        },
        "description": "Cancels a consult by its ID. Court searches already in progress may finish, but no new processing will start.\n\nThis is useful if you submitted a consult by mistake or no longer need the results. Note that **credits are NOT automatically refunded** for user-initiated cancels — only admin-initiated cancels trigger an automatic refund.\n\n**Authentication**: Bearer token (API key) required.\n\n**Errors**:\n- `404` — Consult not found\n- `409` — Consult is already in a terminal state (`done`, `canceled`)"
      },
      "response": [
        {
          "name": "Success",
          "originalRequest": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/consults/{{consultId}}/cancel",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "consults", "{{consultId}}", "cancel"]
            }
          },
          "status": "OK",
          "code": 200,
          "header": [{ "key": "Content-Type", "value": "application/json" }],
          "body": "{\n  \"data\": {\n    \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n    \"status\": \"canceled\"\n  }\n}"
        }
      ]
    },
    {
      "name": "Reprocess Consult",
      "request": {
        "method": "POST",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/api/v1/consults/{{consultId}}/reprocess",
          "host": ["{{baseUrl}}"],
          "path": ["api", "v1", "consults", "{{consultId}}", "reprocess"]
        },
        "description": "Re-queues court searches that ended in error states (`exhausted` or `unavailable`) on a finished consult. Successful searches are not touched.\n\n**Credits are re-charged proportionally** to the number of reprocessable searches: `credits_charged * reprocessable_count / total_courts`. Returns `402` if your balance is insufficient.\n\nUse this when:\n- A court was temporarily unavailable when you first ran the consult\n- You want to retry failed searches without creating a new consult (preserves the consult_id for tracking)\n\n**Authentication**: Bearer token (API key) required.\n\n**Errors**:\n- `402` — Insufficient credits to reprocess\n- `404` — Consult not found\n- `409` — Consult has no court searches in error state, nothing to reprocess"
      }
    }
  ]
}
