{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Versioning","description":"Hyperproof developer resources for custom integrations.","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Welcome to the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Hyperproof TPRM Core API"]}," — the external REST API and webhooks for"," ","Third-Party Risk Management. Use it to manage vendors, read assessments and"," ","documents, follow continuous risk monitoring, request exports, and receive"," ","real-time webhook events."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Base path:"]}," every endpoint is located under ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/tprm-api"]},". Choose your"," ","environment (Development / Demo / Production) from the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Servers"]}," dropdown."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"versioning","__idx":0},"children":["Versioning"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["URLs never contain a version. The API version is selected with the"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-API-Version"]}," request header; omitting it uses the current default (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["v1"]},"):"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"X-API-Version: v1\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Sending an unsupported version returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400"]}," with"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["client_code: request.api_version_unsupported"]},". New versions will be announced"," ","ahead of time — pinning ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-API-Version"]}," explicitly is recommended so a future"," ","default change never breaks your integration."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"quick-start","__idx":1},"children":["Quick start"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"# 1. Exchange your client credentials for a short-lived access token\ncurl -X POST https://api.expent.ai/tprm-api/oauth/token \\\n  -u \"CLIENT_ID:CLIENT_SECRET\" \\\n  --data-urlencode grant_type=client_credentials\n# -> {\"access_token\":\"eyJ…\",\"token_type\":\"Bearer\",\"expires_in\":600,\"scope\":\"…\"}\n\n# 2. Call the API with that token ({} lists all vendors, newest first)\ncurl -X POST https://api.expent.ai/tprm-api/vendors/search \\\n  -H \"Authorization: Bearer ACCESS_TOKEN\" \\\n  -H \"Content-Type: application/json\" -d '{}'\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"where-to-go-next","__idx":2},"children":["Where to go next"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Authentication"]}," — how to get credentials, exchange them for a token, and"," ","limit what a token can do. Start here."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["DPoP"]}," — optional sender-constrained tokens for high-security integrations."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Vendors, Assessments, Monitoring, Documents, Exports, Downloads, Stats"]}," —"," ","the reference pages for each part of the API."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Webhooks"]}," — subscribe to real-time events instead of polling."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"conventions","__idx":3},"children":["Conventions"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A few rules apply across the whole API. They are included here rather than"," ","repeated for each endpoint."]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PATCH vs PUT."]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PATCH"]}," updates only the fields you send. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PUT"]}," is a"," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["full replace"]},": any writable field you leave out is cleared. Always send"," ","the complete resource with a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PUT"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Archive vs delete."]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /vendors/{id}/archive"]}," is reversible and keeps"," ","all of the vendor's data. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DELETE /vendors/{id}"]}," is permanent: it removes the"," ","vendor and everything that belongs to it. When in doubt, archive."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Idempotency."]}," Send an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Idempotency-Key"]}," header on create and export"," ","calls. If you repeat the same request within 24 hours, you get the original"," ","result back instead of a duplicate."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"dates-and-times","__idx":4},"children":["Dates and times"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every date and datetime is returned by the API in ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["your organization's time zone"," ","and date format"]}," (the same settings your Hyperproof UI uses). Datetimes contain"," ","the time after a space — for example, with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MM/DD/YYYY"]}," format (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["-"]}," is always the date separator):"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"\"started_at\": \"07-01-2026 14:30:00\"     # datetime\n\"tprm_contract_end_date\": \"12-31-2026\"  # date-only field\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Send date values in the same format on writes (ISO 8601 is also accepted);"," ","the API converts to UTC for storage."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"errors","__idx":5},"children":["Errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every non-2xx response returns the same JSON structure, shown below. Branch your code on"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["client_code"]}," — it is stable and machine-readable. The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["message"]}," field is"," ","human-readable text and may change over time. The same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request_id"]}," is also"," ","returned in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Request-Id"]}," response header; include it when you contact"," ","support."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\"error\": {\"client_code\": \"vendor.not_found\", \"message\": \"Vendor not found.\",\n           \"request_id\": \"req_9f2…\", \"docs_url\": \"/tprm-api/docs#errors-vendor.not_found\"}}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"retries--429-and-503","__idx":6},"children":["Retries — 429 and 503"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Two statuses can be retried, and both contain a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Retry-After"]}," header (seconds):"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["429"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request.rate_limited"]},") — you exceeded your client's rate limit."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["503"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["internal.service_unavailable"]},") — the service is briefly congested or"," ","a dependency is unavailable. Capacity recovers automatically; your request"," ","was not processed."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle both the same way: wait at least ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Retry-After"]}," seconds, then retry with"," ","exponential backoff and jitter — double the wait after each failed attempt, and"," ","add a small random amount to it so that many clients do not all retry at the"," ","same instant. Treat ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["503"]}," as normal flow-control, not an"," ","outage — during a traffic surge the API sheds excess requests immediately"," ","instead of queueing them, so retries a few seconds later usually succeed."," ","Only non-idempotent requests need care: re-send a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /vendors"]}," retry with"," ","the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Idempotency-Key"]}," so it can never create a duplicate."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"response-headers","__idx":7},"children":["Response headers"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Request-Id"]}," — the correlation id for the request."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Response-Time-Ms"]}," — time spent inside the service, excluding network and"," ","load-balancer time."]}]}]},"headings":[{"value":"Versioning","id":"versioning","depth":2},{"value":"Quick start","id":"quick-start","depth":2},{"value":"Where to go next","id":"where-to-go-next","depth":2},{"value":"Conventions","id":"conventions","depth":2},{"value":"Dates and times","id":"dates-and-times","depth":2},{"value":"Errors","id":"errors","depth":2},{"value":"Retries — 429 and 503","id":"retries--429-and-503","depth":2},{"value":"Response headers","id":"response-headers","depth":2}],"frontmatter":{"seo":{"title":"Versioning"}},"lastModified":"2026-08-11T17:44:00.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/hyperproof-tprm","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}