Migrating from V1
Migrating from V1
The Doppel V2 API preserves the V1 path and request and response contract for
equivalent, non-deprecated endpoints. V2 uses a new authentication model.
For routes that exist in both versions and are not deprecated, migration is
primarily an authentication and path-prefix change. Integrations that use
report routes must also make the resource changes below.
What changed
| V1 | V2 | |
|---|---|---|
| Auth headers | x-api-key (organization-wide), or x-api-key + x-user-api-key (user-specific) | Authorization: Bearer <access_token> |
| Token issuance | Static keys: organization-wide keys are issued by your Doppel sales representative; user-specific keys are self-service from Doppel Vision API settings. | OAuth 2.0 client credentials at POST /oauth/token; access_token expires after expires_in seconds (24 hours at the time of writing) |
| Org scope header | x-organization-code: <ORG> (optional; per the V1 OpenAPI spec, required only when your user belongs to multiple organizations) | Not part of the V2 contract — organization is derived from the org_id claim in the JWT |
| Path prefix | /v1/<resource> | /v2/<resource> |
| Request/response bodies | — | Compatible for equivalent non-deprecated endpoints. V2 adds optional operations and fields. |
If your code uses only routes present in both versions and no deprecated
endpoints (see below), the required code changes are: (1) exchange your client
credentials for a token, (2) replace the V1 auth headers with
Authorization: Bearer ..., (3) drop the x-organization-code header if you
were sending one, and (4) change /v1/ to /v2/ in those request URLs.
V2-only DRP capabilities
V2 adds these Digital Risk Protection capabilities:
- Read one brand with
GET /v2/brand. - Filter alert lists by brand, queue state, severity, entity state, and platform.
- Update alert brand and assignee with
PUT /v2/alert. See Update an alert. - Find alerts that share threat infrastructure. See Find related alerts.
- List takedown requests and read one request with its activity. See Track takedown requests.
- List, create, read, and update typed assets. See Manage assets.
Deprecated endpoints
The following V1 endpoints are deprecated in V2 and are documented as deprecated: true in the V2 OpenAPI spec. They still work, but new integrations should not depend on them.
POST /v2/report— usePOST /v2/alertinsteadGET /v2/report— useGET /v2/alertinsteadPUT /v2/report— usePUT /v2/alertinsteadGET /v2/reports— useGET /v2/alertsinstead
The report resource and the alert resource refer to the same underlying
object. The migration is a rename: replace report with alert (and reports
with alerts) in the path. Request bodies and response shapes are otherwise
identical.
Step 1: Get an OAuth access token
An organization admin or super admin can create a Client ID and Client Secret from the Version 2 tab on the API Settings page in Doppel Vision. Credentials are self-service, and each organization can have up to 10 clients.
Save the Client Secret when you create the client. It is shown only once and cannot be retrieved later. Exchange the credentials for an access token via POST /oauth/token.
For the full token-exchange flow (including refresh handling), see the Authentication guide.
Step 2: Replace your auth headers
V1 (before)
The example below shows the user-specific V1 mode (x-api-key + x-user-api-key) with an explicit x-organization-code. If you were authenticating with x-api-key alone (organization-wide), simply drop the other two headers from the V1 request.
cURL
curl --request GET \
--url "https://api.doppel.com/v1/alerts?queue_state=needs_confirmation" \
--header "x-api-key: <YOUR_ORG_API_KEY>" \
--header "x-user-api-key: <YOUR_USER_API_KEY>" \
--header "x-organization-code: ACM"Python
import requests
response = requests.get(
"https://api.doppel.com/v1/alerts",
headers={
"x-api-key": "<YOUR_ORG_API_KEY>",
"x-user-api-key": "<YOUR_USER_API_KEY>",
"x-organization-code": "ACM",
},
params={"queue_state": "needs_confirmation"},
)Node.js
const url = new URL("https://api.doppel.com/v1/alerts");
url.searchParams.set("queue_state", "needs_confirmation");
const response = await fetch(url, {
headers: {
"x-api-key": "<YOUR_ORG_API_KEY>",
"x-user-api-key": "<YOUR_USER_API_KEY>",
"x-organization-code": "ACM",
},
});V2 (after)
cURL
curl --request GET \
--url "https://api.doppel.com/v2/alerts?queue_state=needs_confirmation" \
--header "Authorization: Bearer <YOUR_ACCESS_TOKEN>"Python
import requests
response = requests.get(
"https://api.doppel.com/v2/alerts",
headers={"Authorization": f"Bearer {access_token}"},
params={"queue_state": "needs_confirmation"},
)Node.js
const url = new URL("https://api.doppel.com/v2/alerts");
url.searchParams.set("queue_state", "needs_confirmation");
const response = await fetch(url, {
headers: { Authorization: `Bearer ${access_token}` },
});For this alert-list request, the query string, response shape, and pagination
behavior are identical to V1; only the auth headers and path prefix change.
Step 3: Handle token expiration
V2 access tokens expire after the expires_in window returned by POST /oauth/token (24 hours at the time of writing). Your client must refresh on 401 Unauthorized, or proactively before expiration. A typical pattern:
import time
import requests
_token = None
_token_expires_at = 0
def get_token() -> str:
global _token, _token_expires_at
if _token and time.time() < _token_expires_at - 60:
return _token
response = requests.post(
"https://api.doppel.com/oauth/token",
json={
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"audience": "doppel-external",
"grant_type": "client_credentials",
},
)
response.raise_for_status()
data = response.json()
_token = data["access_token"]
_token_expires_at = time.time() + data["expires_in"]
return _tokenMigration checklist
- Have an organization admin or super admin create a Client ID and Client Secret in Doppel Vision API Settings.
- Implement the OAuth token-exchange flow (see Authentication).
- Replace
x-api-key(and, if you were sending it,x-user-api-key) withAuthorization: Bearer <token>. - Drop the
x-organization-codeheader if you were sending one — V2 derives the organization from the token. - Confirm each route exists in V2, then change its
/v1/prefix to/v2/. - Add token-refresh handling on
401 Unauthorized. - If you call
/v1/report*or/v1/reports, switch to/v2/alert*or/v2/alerts. - Run your existing integration tests against
/v2/to confirm response shapes are unchanged.
Need help?
If you hit a difference between V1 and V2 that is not covered here, contact your Doppel representative — please include the request URL, the V1 vs V2 response, and any HTTP status codes you observed.
Updated about 1 month ago
