{
  "openapi": "3.1.0",
  "info": {
    "title": "Certvas API",
    "version": "1.0.0",
    "summary": "Point-in-time African and emerging-market fundamentals, procurement and macro data.",
    "description": "Every record carries the source it came from and the licence that source is held under; the register naming all of them is public at https://certvas.com/license-register.\n\nThree properties are worth knowing before you integrate:\n\n1. **Nothing is estimated or interpolated.** Where a value is unknown it is absent rather than guessed, so a null means 'not known', never 'assumed zero'.\n2. **Restatements append a new vintage rather than overwriting**, so `as_of` queries return what was knowable on that date and are reproducible.\n3. **No natural-person data.** Parties not established to be organisations are withheld by an enforced check.\n\nPublished for research and informational use. Not administered as, and not for use as, a regulated benchmark.",
    "contact": {
      "name": "Certvas",
      "email": "mandase@certvas.com",
      "url": "https://certvas.com"
    }
  },
  "servers": [
    {
      "url": "https://api.certvas.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "A sandbox key (`cv_sandbox_public`) works without signup and caps row counts. Paid keys lift the cap."
      }
    }
  },
  "paths": {
    "/v1/status": {
      "get": {
        "summary": "Service and data freshness status.",
        "description": "Liveness plus the build SHA and the freshness of each served dataset.",
        "security": [],
        "responses": {
          "200": {
            "description": "Status document."
          }
        }
      }
    },
    "/v1/fundamentals": {
      "get": {
        "summary": "Point-in-time company fundamentals for listed African issuers.",
        "description": "Reported financial facts. Every record carries the source it came from and the licence class that source is held under. Nothing is estimated or interpolated \u2014 where a value is unknown it is ABSENT rather than filled.",
        "parameters": [
          {
            "name": "dataco_id",
            "in": "query",
            "description": "Certvas ID of the issuer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period_type",
            "in": "query",
            "description": "Reporting cadence, e.g. FY, H1, Q1.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "vintages",
            "in": "query",
            "description": "Return every observed vintage of each fact rather than the latest only. This is what makes restatement analysis possible.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point-in-time date (YYYY-MM-DD). Returns what was KNOWABLE on that date rather than what is known now \u2014 restatements append a new vintage instead of overwriting, so an as-of query is reproducible.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "country",
            "in": "query",
            "description": "ISO 3166-1 alpha-2 country code.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum rows to return. Sandbox keys are capped well below the paid ceiling.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor returned by the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fundamentals facts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/tenders": {
      "get": {
        "summary": "Public-procurement tender releases (OCDS).",
        "description": "Open Contracting releases from portals whose licences permit commercial redistribution. Natural persons are excluded from every published table by an enforced check, not a convention.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "description": "ISO 3166-1 alpha-2 country code.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Procurement category as published by the source portal.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Earliest release date (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Latest release date (YYYY-MM-DD).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum rows to return. Sandbox keys are capped well below the paid ceiling.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor returned by the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tender releases.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/tender-parties": {
      "get": {
        "summary": "Organisations that publish or win tenders.",
        "description": "Buyers and suppliers named in OCDS releases. A party not established to be an organisation is withheld \u2014 the exclusion is enforced at build time and runs conservatively, so some real firms are withheld too.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "description": "ISO 3166-1 alpha-2 country code.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "role",
            "in": "query",
            "description": "Party role, e.g. buyer or supplier.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum rows to return. Sandbox keys are capped well below the paid ceiling.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor returned by the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tender parties.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/macro": {
      "get": {
        "summary": "Macroeconomic indicators for African and emerging markets.",
        "description": "Sourced from the World Bank, IMF and ECB. Attribution and notice conditions travel with the data and are stated per source in the public licence register. Nothing is rebased or interpolated silently.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "description": "ISO 3166-1 alpha-2 country code.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "indicator",
            "in": "query",
            "description": "Indicator code.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "frequency",
            "in": "query",
            "description": "Observation frequency, e.g. A, M, D.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "series",
            "in": "query",
            "description": "Specific series key.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "series_type",
            "in": "query",
            "description": "Series family, e.g. fx or cpi.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point-in-time date (YYYY-MM-DD). Returns what was KNOWABLE on that date rather than what is known now \u2014 restatements append a new vintage instead of overwriting, so an as-of query is reproducible.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum rows to return. Sandbox keys are capped well below the paid ceiling.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor returned by the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Macro observations.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/entities": {
      "get": {
        "summary": "Resolved entity spine.",
        "description": "Organisations and their resolved relationships across Certvas datasets.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "description": "ISO 3166-1 alpha-2 country code.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum rows to return. Sandbox keys are capped well below the paid ceiling.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque pagination cursor returned by the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Entities.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/screen": {
      "get": {
        "summary": "Screen issuers on a metric.",
        "description": "Rank or filter the issuer universe by a supported metric.",
        "parameters": [
          {
            "name": "metric",
            "in": "query",
            "description": "Metric to screen on.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order",
            "in": "query",
            "description": "Sort direction.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point-in-time date (YYYY-MM-DD). Returns what was KNOWABLE on that date rather than what is known now \u2014 restatements append a new vintage instead of overwriting, so an as-of query is reproducible.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "country",
            "in": "query",
            "description": "ISO 3166-1 alpha-2 country code.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum rows to return. Sandbox keys are capped well below the paid ceiling.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Screen results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/signals": {
      "get": {
        "summary": "List published analysed-data signals.",
        "description": "Signal panels computed over the licence-clean spine. Rows live under the `observations` key. Append `/{key}` to fetch one panel.",
        "responses": {
          "200": {
            "description": "Available signals.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/quality-metrics": {
      "get": {
        "summary": "Measured quality metrics for the served datasets.",
        "description": "Published so buyers can verify rather than trust. An unmeasured floor reports as UNMEASURED rather than as a pass.",
        "responses": {
          "200": {
            "description": "Quality metrics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/v1/export": {
      "get": {
        "summary": "Bulk-export manifest.",
        "description": "Published Parquet artifacts and where to fetch them.",
        "responses": {
          "200": {
            "description": "Export manifest.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    }
  }
}
