Trust Signals API Reference
The Futurae Trust Signals API exposes the trust signals derived from observations that the Futurae Sensor SDKs collect on your users' devices and browsers. Each endpoint answers one risk question about a device: whether a browser is driven by a remote access tool, whether it has been seen before, whether two devices are physically near each other, or whether the user has traveled implausibly fast. Each returns a signal you can feed into your own risk engine.
The API is read-only. It retrieves signals computed from observations that the Sensor SDKs collect.
This document describes in detail how to format the HTTP Requests for calling the API endpoints, as well as the format of each individual HTTP request and response.
Current Trust Signals API Version: 1.0.0
Getting Started
Every request names your serviceId (the tenant) and an accountId (the end user). The optional unitId, verificationStatus and interactionId narrow the query; Remote Access Tool requires all three. See Identifiers.
Postman Sample Collection
To help you with integration, we provide a postman collection with a sample request for every Trust Signals API endpoint.
Once you import the collection into Postman, you will need to edit it and adjust the following collection variables:
| Variable | Value |
|---|---|
| hostname | The Signals API hostname, ts-signals-public.futurae.com
|
| access_token | An OAuth2 bearer token with audience ts-signals-public.futurae.com and scope signals:read (see Request Authentication) |
| serviceId | Your tenant identifier, a UUID provided by Futurae |
| accountId | The account ID of the end user you are querying |
| unitId | The unit ID to read |
| baselineUnitId / subjectUnitId | The two units compared by the paired signals |
| verificationStatus |
verified, unverified or fraud
|
| interactionId | The interaction ID to read, matched as a prefix, or exactly on Remote Access Tool. Requires verificationStatus
|
Request Format
All endpoints are served from https://ts-signals-public.futurae.com under the /api/v1/ prefix and return application/json. Signal endpoints are grouped under /api/v1/signals/.
All parameters are supplied as query parameters, with the single exception of Get Remote Access Tool Signals (Batch), which takes a JSON array as its request body.
Headers
| Parameter | Description |
|---|---|
Authorizationstringrequired |
OAuth2 bearer token with the signals:read scope. See Request Authentication. |
Request Authentication
Authorization header format:
Authorization: Bearer <token>
Requests are authenticated with an OAuth2 bearer token, obtained through the Client Credentials flow from the Futurae authorization server, auth.futurae.com.
Provisioned credentials
Requesting a signals token:
curl --location 'https://auth.futurae.com/oauth/v2/token?grant_type=client_credentials&scope=urn'\
'%3Azitadel%3Aiam%3Aorg%3Aproject%3Aid%3Ats-signals-public.futurae.com%3Aaud' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic <base64(client_id:client_secret)>'
Futurae provisions two OAuth2 clients per integration, each with its own client_id and client_secret. Each client_id is a UUID, distinct from your serviceId.
| Client | Audience | OAuth2 scope |
|---|---|---|
| Retrieval | ts-signals-public.futurae.com |
signals:read |
| Collection | ts-collection-public.futurae.com |
observations:write |
This API accepts only a token issued to the retrieval client, with audience ts-signals-public.futurae.com and scope signals:read; any other token is rejected with 403.
The client_id and client_secret are passed to the token endpoint via HTTP Basic authentication. The resulting token is valid for all accounts within your tenant.
Token claims
Alongside the standard claims (iss, aud, exp, nbf, iat, jti), the token carries:
| Claim | Description |
|---|---|
| service_id | Your tenant identifier. The serviceId on every request must equal this claim. See Tenant Isolation. |
| scope | Must contain signals:read. |
What your request must satisfy
| Requirement | Description |
|---|---|
| Token | Audience ts-signals-public.futurae.com, scope signals:read, presented as Authorization: Bearer <token>, unexpired. |
| serviceId | Required on every request, and must equal the service_id claim on your token. See Tenant Isolation. |
| Identifiers |
accountId, unitId, interactionId and the paired variants must satisfy the constraints in Identifiers. |
| verificationStatus | When supplied, one of verified, unverified or fraud. Paired variants follow the same rule. |
A 401 means the token is missing, malformed, expired, carries an invalid signature, or uses a scheme other than Bearer. A 403 means the token is valid but the request is not permitted with it: the wrong scope or audience, or a serviceId that differs from the token claim. An identifier that breaks its documented constraints is rejected with 400.
Tenant Isolation
serviceId is the tenant boundary, and it is enforced on every request: the value you supply must equal the service_id claim on your access token. A mismatch is rejected with 403.
service_id is a signed token claim set by the Authorization Server, so the serviceId you send is always checked against the tenant the token was issued for.
Identifiers
Observations are stored under these identifiers and cannot be rekeyed afterwards, so settle your convention before production.
| Identifier | Purpose | Constraint |
|---|---|---|
| serviceId | Your tenant. Provided by Futurae; must match the token claim. Required. | A UUID |
| accountId | The end user. Opaque, chosen by you. Required. | ^[A-Za-z0-9-]{1,50}$ |
| unitId | The unit the observations were collected under. Optional, except for Remote Access Tool. |
^[A-Za-z0-9-]+$, maximum 1000 characters |
| verificationStatus | The label the observations were collected with. Optional, except for Remote Access Tool. |
verified, unverified or fraud
|
| interactionId | One interaction within a unit. Optional, except for Remote Access Tool. |
^[A-Za-z0-9-]+$, maximum 1000 characters |
Matching
Each identifier you supply constrains which observations a query considers. An identifier you omit is left unconstrained. unitId, verificationStatus and interactionId are optional, except for Remote Access Tool, which requires all three.
The optional identifiers must be supplied in order: verificationStatus requires unitId, and interactionId requires verificationStatus. A request that breaks this order is rejected with 400. On the paired signals the same rule applies to each side.
| Identifier | Matching |
|---|---|
| serviceId | Always required, matched exactly. |
| unitId | Matched exactly. |
| verificationStatus | Matched exactly. |
| interactionId | Matched as a prefix: session-9f2c matches session-9f2c, session-9f2c-login and session-9f2c-payment. Remote Access Tool is the exception: it matches interactionId exactly, because it evaluates one session. |
Build interactionId from its most general part to its most specific, such as a session identifier followed by a page identifier, so that a shorter value selects a predictable group of interactions.
Paired signals
Latest Proximity, Historical Proximity and New Browser compare two sides. Every identifier except serviceId splits into a subject* / baseline* pair, and each side is narrowed independently by the rules above:
| Side | Meaning |
|---|---|
| baseline | The reference side: the unit whose history or position the subject is evaluated against. |
| subject | The side being evaluated. |
Response Format
A successful signal response:
{
"signalType": "active_call",
"success": true,
"result": { "onCall": true },
"observationTime": "2026-04-22T14:15:20Z"
}
The same signal when it could not be computed:
{
"signalType": "active_call",
"success": false,
"reason": "insufficient_observations"
}
Every signal endpoint returns the same envelope: a signalType naming the signal, a success boolean, and, when successful, a result plus the timestamps of the observations it was computed from.
result is always a JSON object, for every signal.
A request that is well-formed and authorized but finds too few observations still returns 200, with success: false and a reason explaining why. Branch on success as well as on the HTTP status.
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
The computed signal. Shape depends on the endpoint. Omitted when success is false. |
observationTimestringoptional |
RFC 3339 timestamp of the observation the result was computed from. Omitted when success is false. |
observationTimesByUnitobjectoptional |
Returned by Latest Proximity and Historical Proximity instead of observationTime. Holds two RFC 3339 timestamps, one per side, under the fixed keys baselineUnitId and subjectUnitId. Omitted when success is false. |
HTTP Response Codes
| HTTP Code | Meaning |
|---|---|
200 |
The request was successful. Check the success field to learn whether the signal itself could be computed. |
400 |
Invalid or missing request parameters, including optional identifiers supplied out of order (see Matching). Also returned bare by the batch endpoint for a wrong Content-Type or an out-of-range batch size. |
401 |
Authorization information is missing, or the token is invalid. |
403 |
Authenticated, but not permitted: wrong audience or scope, an account outside your tenant, or a serviceId that differs from the token claim. Not returned by the batch endpoint, which reports authorization failures per item. |
Signals
Get Latest Proximity Signal
Example request:
GET /api/v1/signals/latest-proximity?serviceId=f47ac10b-58cc-4372-a567-0e02b2c3d479&subjectAccountId=user-123&subjectUnitId=webApp&subjectVerificationStatus=verified&baselineUnitId=iosApp&baselineVerificationStatus=verified
GET /api/v1/signals/latest-proximity
Scores how likely it is that two devices are in the same place right now, by comparing their most recent observations. Typical use is to check that a user's phone is near the browser they are logging in from.
The confidence is accompanied by the supporting signals that produced it: overlapping IP addresses, matching Wi-Fi networks and shared nearby Bluetooth devices, so you can see what drove the result.
| Applicable to | Mobile and/or Browser |
| Data sources | Mobile: shared Wi-Fi networks, Bluetooth devices, public IP address, geolocation. Browser: public IP address, IP geolocation. |
| Use case | Detecting fraud where an attacker authenticates remotely while the legitimate user's phone is elsewhere. |
Query parameters
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID provided by Futurae. Must equal the service_id claim on the access token, or the request is rejected with 403. |
subjectAccountIdstringrequired |
End-user identifier owning the subject side, the side evaluated against the baseline. |
subjectUnitIdstringoptional |
unitId of the subject side, matched exactly. Required if subjectVerificationStatus is set. |
subjectVerificationStatusstringoptional |
verified, unverified or fraud for the subject side, matched exactly. Requires subjectUnitId, and is required if subjectInteractionId is set. |
subjectInteractionIdstringoptional |
interactionId of the subject side, matched as a prefix. Requires subjectVerificationStatus. |
subjectSdkVersionIdstringoptional |
Restricts the subject side to one SDK version. Same format as sdkVersionId. |
baselineAccountIdstringoptional |
End-user identifier owning the baseline side, the reference side. Omit when both sides belong to subjectAccountId. |
baselineUnitIdstringoptional |
unitId of the baseline side, matched exactly. Required if baselineVerificationStatus is set. |
baselineVerificationStatusstringoptional |
verified, unverified or fraud for the baseline side, matched exactly. Requires baselineUnitId, and is required if baselineInteractionId is set. |
baselineInteractionIdstringoptional |
interactionId of the baseline side, matched as a prefix. Requires baselineVerificationStatus. |
baselineSdkVersionIdstringoptional |
Restricts the baseline side to one SDK version. Same format as sdkVersionId. |
supportingSignalstringoptional |
Restricts computation to a single supporting signal type. See Supporting Signals. |
windowStartstringoptional |
Start of the observation window, RFC 3339 UTC, for example 2026-04-22T09:15:20Z.The window may span at most 31 days. Defaults to 31 days ago. |
windowEndstringoptional |
End of the observation window, RFC 3339 UTC. Defaults to the current time. |
Response 200
Example response:
{
"signalType": "latest_proximity",
"success": true,
"result": {
"proximityConfidence": 0.94,
"supportingSignals": [
{ "type": "reportedIpOverlap", "details": { "matched": true, "matchCount": null } },
{ "type": "wifiNetworkOverlap", "details": { "matched": true, "matchCount": 2 } },
{ "type": "connectedWifiNetworkOverlap", "details": { "matched": true, "matchCount": null } },
{ "type": "connectedBleDeviceOverlap", "details": { "matched": true, "matchCount": 1 } },
{ "type": "locationOverlap", "details": { "matched": true, "matchCount": null } },
{ "type": "ingressIpCountryOverlap", "details": { "matched": true, "matchCount": null } },
{ "type": "ingressIpOverlap", "details": { "matched": true, "matchCount": null } }
]
},
"observationTimesByUnit": {
"baselineUnitId": "2026-05-12T10:23:38.000Z",
"subjectUnitId": "2026-05-12T10:23:41.000Z"
}
}
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
The proximity result. Omitted when success is false. |
result.proximityConfidencenumber
|
Float in [0, 1]. Higher values indicate the devices are more likely co-located. |
result.supportingSignalsarray
|
One entry per supporting signal type evaluated. See Supporting Signals. |
observationTimesByUnitobjectoptional |
RFC 3339 timestamps of the latest observation used for each side, under the keys baselineUnitId and subjectUnitId. Omitted when success is false. |
Get Historical Proximity Signal
Example request:
GET /api/v1/signals/historical-proximity?serviceId=f47ac10b-58cc-4372-a567-0e02b2c3d479&subjectAccountId=user-123&subjectUnitId=androidApp&subjectVerificationStatus=verified&baselineUnitId=iosApp&baselineVerificationStatus=verified&windowStart=2026-05-12T08:00:00Z&windowEnd=2026-05-12T09:00:00Z
GET /api/v1/signals/historical-proximity
The time-range counterpart to Latest Proximity. Rather than comparing only the latest observation from each unit, it searches all observations in the window for the best matching pair.
Two independent best matches are returned: bestMatch over sensor observations, and bestIngressMatch over ingress-IP observations. Either may be null when no pair of that kind could be scored.
| Applicable to | Mobile and/or Browser |
| Data sources | Same as Latest Proximity. |
| Use case 1 | Retroactive fraud investigation: were two devices active during a suspicious transaction ever co-located beforehand? |
| Use case 2 | New authenticator enrollment: confirm a new device has previously been co-located with a trusted one. |
Query parameters
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID provided by Futurae. Must equal the service_id claim on the access token, or the request is rejected with 403. |
subjectAccountIdstringrequired |
End-user identifier owning the subject side, the side evaluated against the baseline. |
subjectUnitIdstringoptional |
unitId of the subject side, matched exactly. Required if subjectVerificationStatus is set. |
subjectVerificationStatusstringoptional |
verified, unverified or fraud for the subject side, matched exactly. Requires subjectUnitId, and is required if subjectInteractionId is set. |
subjectInteractionIdstringoptional |
interactionId of the subject side, matched as a prefix. Requires subjectVerificationStatus. |
subjectSdkVersionIdstringoptional |
Restricts the subject side to one SDK version. Same format as sdkVersionId. |
baselineAccountIdstringoptional |
End-user identifier owning the baseline side, the reference side. Omit when both sides belong to subjectAccountId. |
baselineUnitIdstringoptional |
unitId of the baseline side, matched exactly. Required if baselineVerificationStatus is set. |
baselineVerificationStatusstringoptional |
verified, unverified or fraud for the baseline side, matched exactly. Requires baselineUnitId, and is required if baselineInteractionId is set. |
baselineInteractionIdstringoptional |
interactionId of the baseline side, matched as a prefix. Requires baselineVerificationStatus. |
baselineSdkVersionIdstringoptional |
Restricts the baseline side to one SDK version. Same format as sdkVersionId. |
supportingSignalstringoptional |
Restricts computation to a single supporting signal type. See Supporting Signals. |
windowStartstringoptional |
Start of the observation window, RFC 3339 UTC, for example 2026-04-22T09:15:20Z.The window may span at most 31 days. Defaults to 31 days ago. |
windowEndstringoptional |
End of the observation window, RFC 3339 UTC. Defaults to the current time. |
Response 200
Example response:
{
"signalType": "historical_proximity",
"success": true,
"result": {
"bestMatch": {
"proximityConfidence": 0.74,
"supportingSignals": [
{ "type": "wifiNetworkOverlap", "details": { "matched": true, "matchCount": 2 } },
{ "type": "locationOverlap", "details": { "matched": true, "matchCount": null } }
]
},
"bestIngressMatch": {
"proximityConfidence": 0.66,
"supportingSignals": [
{ "type": "ingressIpCountryOverlap", "details": { "matched": true, "matchCount": null } },
{ "type": "ingressIpCityOverlap", "details": { "matched": false, "matchCount": null } }
]
}
},
"observationTimesByUnit": {
"baselineUnitId": "2026-05-12T08:14:02.000Z",
"subjectUnitId": "2026-05-12T08:57:11.000Z"
}
}
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
The best matches found in the window. Omitted when success is false. |
result.bestMatchobjectnullable |
Best matching pair of sensor observations, or null when none could be scored. Carries proximityConfidence and supportingSignals. Only non-ingress signals appear here. |
result.bestIngressMatchobjectnullable |
Best matching pair of ingress-IP observations, or null. Carries proximityConfidence and supportingSignals. Only ingress signals appear here. |
observationTimesByUnitobjectoptional |
RFC 3339 timestamps of the best-matching observation for each side, under the keys baselineUnitId and subjectUnitId. Omitted when success is false. |
Get New Browser Signal
Example request:
GET /api/v1/signals/new-browser?serviceId=f47ac10b-58cc-4372-a567-0e02b2c3d479&subjectAccountId=temp-preauth-9f2c&subjectUnitId=webApp&subjectVerificationStatus=unverified&baselineAccountId=user-123&baselineUnitId=webApp&baselineVerificationStatus=verified
GET /api/v1/signals/new-browser
Answers "have we seen this browser before?". It takes the latest browser fingerprint of the subject unit and checks whether it already appears in the baseline unit's observation history.
| Applicable to | Browser only |
| Data sources | Browser fingerprint |
| Use case | Trigger additional verification when a user authenticates from a previously unseen browser profile, which may indicate account takeover. |
How the result is determined
- If the subject side has no complete fingerprint observation, the signal returns
success: falsewithreason: insufficient_observations. - If
baselineAccountIdis omitted, the latest subject fingerprint is compared against the subject side's own earlier observations in the window, excluding thecooldownSecondsperiod. - Otherwise the baseline side's history in the window is checked, excluding the
cooldownSecondsperiod. If it is empty,knownisfalse. - Otherwise the latest subject fingerprint is compared against every baseline observation in that history.
knownistrueif any match.
Query parameters
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID provided by Futurae. Must equal the service_id claim on the access token, or the request is rejected with 403. |
subjectAccountIdstringrequired |
End-user identifier owning the evaluated side. May be a temporary placeholder. See above. |
subjectUnitIdstringoptional |
unitId of the evaluated side, matched exactly. Its latest fingerprint observation is the one compared. Required if subjectVerificationStatus is set. |
subjectVerificationStatusstringoptional |
verified, unverified or fraud for the evaluated side, matched exactly. Requires subjectUnitId, and is required if subjectInteractionId is set. |
subjectInteractionIdstringoptional |
interactionId of the evaluated side, matched as a prefix. Requires subjectVerificationStatus. |
baselineAccountIdstringoptional |
End-user identifier owning the reference side. Omit to compare the subject's latest fingerprint against the subject side's own earlier observations; baselineUnitId, baselineVerificationStatus and baselineInteractionId are then ignored. |
baselineUnitIdstringoptional |
unitId of the reference side, whose observation history the fingerprint is compared against, matched exactly. Required if baselineVerificationStatus is set. Ignored without baselineAccountId. |
baselineVerificationStatusstringoptional |
verified, unverified or fraud for the reference side, matched exactly. Requires baselineUnitId, and is required if baselineInteractionId is set. Ignored without baselineAccountId. |
baselineInteractionIdstringoptional |
interactionId of the reference side, matched as a prefix. Requires baselineVerificationStatus. Ignored without baselineAccountId. |
subjectSdkVersionIdstringoptional |
Restricts the evaluated side to one SDK version. Same format as sdkVersionId on the single-unit signals. |
baselineSdkVersionIdstringoptional |
Restricts the reference side to one SDK version. Same format as subjectSdkVersionId. |
matchScopestringoptional default: browser_profile
|
How much of the fingerprint must match.browser_profile compares only the summary browser_* fields (name, OS, version).full_fingerprint additionally compares the full fingerprint blob, which is stricter. |
cooldownSecondsintegeroptional default: 3600
|
Excludes fingerprint observations newer than now − cooldownSeconds from the comparison. Minimum 0. See Matching cooldown. |
windowStartstringoptional |
Start of the observation window, RFC 3339 UTC, for example 2026-04-22T09:15:20Z.The window may span at most 31 days. Defaults to 31 days ago. |
windowEndstringoptional |
End of the observation window, RFC 3339 UTC. Defaults to the current time. |
Matching cooldown
Only fingerprints older than the cooldown cutoff count toward a known: true result. This matters in two ways:
- Ignoring a session's own resubmissions. The SDK rewrites the fingerprint repeatedly during a session. Without a cooldown a brand-new device could match its own recent submissions and wrongly come back as known. This matters only when the subject and baseline sides cover the same unit.
- Giving recent sessions time to be trusted. A session from moments ago may not yet be confirmed legitimate. The cooldown holds it back from counting as trusted history.
Response 200
Example response:
{
"signalType": "new_browser",
"success": true,
"result": { "known": false },
"mismatchedFields": ["browser_version"],
"unitId": "webApp",
"verificationStatus": "unverified",
"interactionId": "session-9f2c-login",
"observationTime": "2026-05-12T10:23:41.000Z"
}
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
Whether the browser profile has been seen before. Omitted when success is false. |
result.knownboolean
|
true if the latest subject fingerprint matches at least one baseline observation older than the cooldown cutoff. Which fields must match depends on matchScope. |
mismatchedFieldsarrayoptional |
Present only when result.known is false: the fingerprint fields of the latest observation that differed from the closest earlier observation, the one differing in the fewest fields. Omitted when there was no earlier observation to compare against. |
unitIdstringoptional |
unitId of the observation the result was computed from. |
verificationStatusstringoptional |
verificationStatus of that observation. |
interactionIdstringoptional |
interactionId of that observation. |
observationTimestringoptional |
RFC 3339 timestamp of the latest subject observation used. |
Get Geolocation Signal
Example request:
GET /api/v1/signals/geolocation?serviceId=f47ac10b-58cc-4372-a567-0e02b2c3d479&accountId=user-123&unitId=iosApp&verificationStatus=verified
GET /api/v1/signals/geolocation
Returns the best available location estimate for a unit, drawing from GPS (mobile only) and ingress IP geolocation. Each source is returned as a separate datapoint so you can apply your own resolution and confidence logic.
| Applicable to | Mobile or Browser |
| Data sources | GPS (mobile only), public IP geolocation |
| Use case | Enforce country- or region-based access policies. |
Query parameters
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID provided by Futurae. Must equal the service_id claim on the access token, or the request is rejected with 403. |
accountIdstringrequired |
Opaque identifier of the end user, chosen and managed by you. Alphanumerics and hyphens only ( ^[A-Za-z0-9-]{1,50}$), maximum 50 characters. |
unitIdstringoptional |
Matched exactly. Omit to consider every unit under serviceId. Required if verificationStatus is set.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
verificationStatusstringoptional |
verified, unverified or fraud, matched exactly. Omit to consider every label. Requires unitId, and is required if interactionId is set. See Verification Status. |
interactionIdstringoptional |
Matched as a prefix: considers every interaction whose interactionId starts with this value. Omit to consider every interaction. Requires verificationStatus.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
sdkVersionIdstringoptional |
Restricts the read to observations from one SDK version, assigned by Futurae. Omit to consider every version. Letters, digits, ., - and / only (^[A-Za-z0-9.\-/]+$), maximum 50 characters. |
windowStartstringoptional |
Start of the observation window, RFC 3339 UTC, for example 2026-04-22T09:15:20Z.The window may span at most 31 days. Defaults to 31 days ago. |
windowEndstringoptional |
End of the observation window, RFC 3339 UTC. Defaults to the current time. |
Response 200
Example response:
{
"signalType": "geolocation",
"success": true,
"result": {
"datapoints": [
{ "name": "geo", "observationTime": "2026-04-22T14:15:20Z", "valueType": "geo", "lat": 47.4979, "lon": 19.0402,
"unitId": "iosApp", "verificationStatus": "verified", "interactionId": "installation-4b1e" },
{ "name": "ingress_ip_geo", "observationTime": "2026-04-22T14:15:20Z", "valueType": "geo", "lat": 47.49, "lon": 19.04,
"unitId": "iosApp", "verificationStatus": "verified", "interactionId": "installation-4b1e" },
{ "name": "ingress_ip_city", "observationTime": "2026-04-22T14:15:20Z", "valueType": "string", "value": "Budapest",
"unitId": "iosApp", "verificationStatus": "verified", "interactionId": "installation-4b1e" },
{ "name": "ingress_ip_country", "observationTime": "2026-04-22T14:15:20Z", "valueType": "string", "value": "HU",
"unitId": "iosApp", "verificationStatus": "verified", "interactionId": "installation-4b1e" }
]
},
"observationTime": "2026-04-22T14:15:20Z"
}
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
Wraps the returned datapoints. Omitted when success is false. |
result.datapointsarray
|
One entry per datapoint with at least one observation in the window, each carrying the latest value for that datapoint and the unitId, verificationStatus and interactionId of the observation that reported it. See Datapoints. |
observationTimestringoptional |
RFC 3339 timestamp of the latest observation used. |
Datapoints that can appear, each present only when data exists for it:
| Name | valueType |
Source |
|---|---|---|
geo |
geo |
Sensor |
ingress_ip_geo |
geo |
Network |
ingress_ip_lat |
string |
Network |
ingress_ip_lon |
string |
Network |
ingress_ip_city |
string |
Network |
ingress_ip_region |
string |
Network |
ingress_ip_country |
string |
Network |
ingress_ip_continent |
string |
Network |
Get Geovelocity Signal
Example request:
GET /api/v1/signals/geovelocity?serviceId=f47ac10b-58cc-4372-a567-0e02b2c3d479&accountId=user-123&unitId=iosApp&verificationStatus=verified&windowStart=2026-05-12T08:00:00Z&windowEnd=2026-05-12T10:00:00Z
GET /api/v1/signals/geovelocity
Flags physically impossible travel of the user's mobile device: it computes the maximum speed implied by pairs of location observations in the window and compares it against a plausibility threshold.
| Applicable to | Mobile only |
| Data sources | GPS observations |
| Use case | Detect credential theft or session hijacking: a device appearing in Zurich and New York within an hour should be flagged for step-up or blocked. |
Query parameters
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID provided by Futurae. Must equal the service_id claim on the access token, or the request is rejected with 403. |
accountIdstringrequired |
Opaque identifier of the end user, chosen and managed by you. Alphanumerics and hyphens only ( ^[A-Za-z0-9-]{1,50}$), maximum 50 characters. |
unitIdstringoptional |
Matched exactly. Omit to consider every unit under serviceId. Required if verificationStatus is set.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
verificationStatusstringoptional |
verified, unverified or fraud, matched exactly. Omit to consider every label. Requires unitId, and is required if interactionId is set. See Verification Status. |
interactionIdstringoptional |
Matched as a prefix: considers every interaction whose interactionId starts with this value. Omit to consider every interaction. Requires verificationStatus.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
sdkVersionIdstringoptional |
Restricts the read to observations from one SDK version, assigned by Futurae. Omit to consider every version. Letters, digits, ., - and / only (^[A-Za-z0-9.\-/]+$), maximum 50 characters. |
windowStartstringoptional |
Start of the observation window, RFC 3339 UTC, for example 2026-04-22T09:15:20Z.The window may span at most 31 days. Defaults to 31 days ago. |
windowEndstringoptional |
End of the observation window, RFC 3339 UTC. Defaults to the current time. |
Response 200
Example response:
{
"signalType": "geovelocity",
"success": true,
"result": {
"anomaly": true,
"maxSpeedKmh": 1520.4,
"sources": [
{
"locationSource": "gps",
"evaluated": true,
"anomaly": true,
"maxSpeedKmh": 1520.4,
"thresholdKmh": 900,
"evaluatedPairCount": 1,
"fastestPair": {
"fromObservationTime": "2026-04-22T09:15:20Z",
"toObservationTime": "2026-04-22T10:05:11Z",
"fromUnitId": "iosApp",
"fromVerificationStatus": "verified",
"fromInteractionId": "installation-4b1e",
"toUnitId": "iosApp",
"toVerificationStatus": "verified",
"toInteractionId": "installation-4b1e",
"distanceKm": 1263.1,
"elapsedSeconds": 2991,
"speedKmh": 1520.4
}
}
]
},
"observationTime": "2026-04-22T10:05:11Z"
}
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
The geovelocity verdict. Omitted when success is false. |
result.anomalyboolean
|
true if any evaluated source flags physically impossible travel. |
result.maxSpeedKmhnumbernullable |
Highest maxSpeedKmh across all sources, in km/h. null when no source could be scored. |
result.sourcesarray
|
One entry per location source evaluated. See Geovelocity Source. Currently always a single gps entry; more sources may be added without reshaping the response. |
observationTimestringoptional |
RFC 3339 timestamp of the latest observation used. |
Get Active Call Signal
Example request:
GET /api/v1/signals/active-call?serviceId=f47ac10b-58cc-4372-a567-0e02b2c3d479&accountId=user-123&unitId=iosApp&verificationStatus=verified
GET /api/v1/signals/active-call
Reports whether the device was on a phone call at its most recent observation. This is a signal against social-engineering attacks, where a victim is on the phone with the attacker while authorizing a transaction.
| Applicable to | Mobile only |
| Data sources | Telephony state |
| Use case | Detect vishing: an active call during a transaction confirmation suggests an attacker may be guiding the user. |
Query parameters
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID provided by Futurae. Must equal the service_id claim on the access token, or the request is rejected with 403. |
accountIdstringrequired |
Opaque identifier of the end user, chosen and managed by you. Alphanumerics and hyphens only ( ^[A-Za-z0-9-]{1,50}$), maximum 50 characters. |
unitIdstringoptional |
Matched exactly. Omit to consider every unit under serviceId. Required if verificationStatus is set.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
verificationStatusstringoptional |
verified, unverified or fraud, matched exactly. Omit to consider every label. Requires unitId, and is required if interactionId is set. See Verification Status. |
interactionIdstringoptional |
Matched as a prefix: considers every interaction whose interactionId starts with this value. Omit to consider every interaction. Requires verificationStatus.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
sdkVersionIdstringoptional |
Restricts the read to observations from one SDK version, assigned by Futurae. Omit to consider every version. Letters, digits, ., - and / only (^[A-Za-z0-9.\-/]+$), maximum 50 characters. |
windowStartstringoptional |
Start of the observation window, RFC 3339 UTC, for example 2026-04-22T09:15:20Z.The window may span at most 31 days. Defaults to 31 days ago. |
windowEndstringoptional |
End of the observation window, RFC 3339 UTC. Defaults to the current time. |
Response 200
Example response:
{
"signalType": "active_call",
"success": true,
"result": { "onCall": true },
"unitId": "iosApp",
"verificationStatus": "verified",
"interactionId": "installation-4b1e",
"observationTime": "2026-05-12T10:22:58.000Z"
}
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
The call-state verdict. Omitted when success is false. |
result.onCallboolean
|
true if an active phone call was detected at the most recent observation. |
unitIdstringoptional |
unitId of the observation the result was computed from. |
verificationStatusstringoptional |
verificationStatus of that observation. |
interactionIdstringoptional |
interactionId of that observation. |
observationTimestringoptional |
RFC 3339 timestamp of the latest telephony-state observation. |
Get Remote Access Tool Signal
Example request:
GET /api/v1/signals/remote-access-tool?serviceId=f47ac10b-58cc-4372-a567-0e02b2c3d479&accountId=user-123&unitId=webApp&verificationStatus=verified&interactionId=session-9f2c-payment
GET /api/v1/signals/remote-access-tool
Scores the likelihood that a browser is being operated via remote desktop software rather than directly by a human, which is the signature of a remote-access scam. The classifier runs on browser fingerprint characteristics, keyboard dynamics and mouse movement patterns.
| Applicable to | Browser only |
| Data sources | Browser fingerprint, keyboard dynamics, mouse movement patterns |
| Use case | Detect remote-access fraud: an attacker controlling the victim's browser with tooling such as TeamViewer. |
Scoring prerequisites
All four must hold, or the signal returns success: false with the reason shown:
| Condition | Requirement |
reason if unmet |
|---|---|---|
| Supported platform | A desktop browser and operating system combination the classifier supports | unsupported_platform |
| Mouse movement data | Enough mouse movement events in the session to characterize it | insufficient_observations |
| Keystroke data | Enough keystroke press events in the session to characterize it | insufficient_observations |
| User baseline | Enough prior sessions for the same user and platform, containing both mouse movement and keystroke events | no_user_baseline |
Baseline anchoring
The classifier compares each session against a per-user, per-platform baseline built from that user's own past sessions, as they stood at the moment the scored session took place. A session queried long after it occurred is scored against the baseline it had at the time.
Query parameters
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID provided by Futurae. Must equal the service_id claim on the access token, or the request is rejected with 403. |
accountIdstringrequired |
Opaque identifier of the end user, chosen and managed by you. Alphanumerics and hyphens only ( ^[A-Za-z0-9-]{1,50}$), maximum 50 characters. |
unitIdstringrequired |
unitId of the session to score, matched exactly.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
verificationStatusstringrequired |
verified, unverified or fraud, matched exactly. See Verification Status. |
interactionIdstringrequired |
interactionId of the session to score, matched exactly, not as a prefix.Alphanumerics and hyphens only ( ^[A-Za-z0-9-]+$), maximum 1000 characters. |
sdkVersionIdstringoptional |
Restricts the read to observations from one SDK version, assigned by Futurae. Omit to consider every version. Letters, digits, ., - and / only (^[A-Za-z0-9.\-/]+$), maximum 50 characters. |
baselineScopestringoptional default: interaction_anchored
|
Which stored sessions form the baseline.interaction_anchored uses only sessions recorded before the scored session, and excludes the scored session itself, giving a stable score.full_history uses every stored session, including the scored one and any recorded after it, at the cost of that stability: re-querying later can return a different score. |
Response 200
Example response:
{
"signalType": "remote_access_tool",
"success": true,
"result": {
"anomaly": true,
"anomalyConfidence": 0.82
},
"unitId": "webApp",
"verificationStatus": "verified",
"interactionId": "session-9f2c-payment",
"observationTime": "2026-04-22T14:15:20Z"
}
| Parameter | Description |
|---|---|
signalTypestring
|
Stable identifier of the signal type. |
successboolean
|
Whether the signal was computed. When false, reason explains why and result is omitted. |
reasonstringoptional |
Machine-readable failure reason, present when success is false. See Failure Reasons. |
resultobjectoptional |
The verdict. Omitted when success is false. |
result.anomalyboolean
|
true if remote-control use is suspected. |
result.anomalyConfidencenumber
|
Float in [0, 1]. 0.0 means no indication of remote control; 1.0 is highest confidence. |
unitIdstringoptional |
unitId of the observation the result was computed from. |
verificationStatusstringoptional |
verificationStatus of that observation. |
interactionIdstringoptional |
interactionId of that observation. |
observationTimestringoptional |
RFC 3339 timestamp of the latest observation used. |
Get Remote Access Tool Signals (Batch)
Example request:
POST /api/v1/signals/remote-access-tool
Content-Type: application/json
Example request body:
[
{ "serviceId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "accountId": "user-123", "unitId": "webApp", "verificationStatus": "verified", "interactionId": "session-9f2c-payment" },
{ "serviceId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "accountId": "user-456", "unitId": "webApp", "verificationStatus": "unverified", "interactionId": "session-71ad-login" }
]
POST /api/v1/signals/remote-access-tool
Batch variant of Get Remote Access Tool Signal. Scores many sessions in one call, using the same logic as the single-item endpoint.
Headers
| Parameter | Description |
|---|---|
Authorizationstringrequired |
OAuth2 bearer token with the signals:read scope. See Request Authentication. |
Content-Typestringrequired |
Must be application/json. Any other media type is rejected with a bare 400. |
Request body
A JSON array of 1–100 objects. An empty or oversized batch is rejected with a bare 400.
| Parameter | Description |
|---|---|
serviceIdstringrequired |
Your tenant identifier, a UUID. Must equal the service_id claim on the access token, or the item fails with reason: forbidden. |
accountIdstringrequired |
End-user identifier. |
unitIdstringrequired |
Same rules as on the single-item endpoint. |
verificationStatusstringrequired |
Same rules as on the single-item endpoint. |
interactionIdstringrequired |
Same rules as on the single-item endpoint. |
sdkVersionIdstringoptional |
Same rules as on the single-item endpoint. |
Fixed behavior
Every item in a batch is scored identically:
| Behavior | Batch value |
|---|---|
| Lookback window | Fixed server-side, as for the single-item endpoint. |
| Identifier matching | As for the single-item endpoint: unitId and verificationStatus matched exactly, and interactionId matched exactly, not as a prefix. See Matching. |
baselineScope |
Always interaction_anchored for every item in a batch. |
Results are returned in the same order as the request. A single request can mix sessions the token is and isn't authorized for, so authorization failures are reported per item with reason: forbidden rather than as a top-level 403.
Response 200
Example response:
{
"signalType": "remote_access_tool",
"results": [
{
"accountId": "user-123",
"unitId": "webApp",
"verificationStatus": "verified",
"interactionId": "session-9f2c-payment",
"success": false,
"reason": "insufficient_observations"
},
{
"accountId": "user-456",
"unitId": "webApp",
"verificationStatus": "unverified",
"interactionId": "session-71ad-login",
"success": true,
"result": { "anomaly": false, "anomalyConfidence": 0.04 },
"observationTime": "2026-04-22T14:15:20Z"
}
]
}
| Parameter | Description |
|---|---|
signalTypestring
|
Always remote_access_tool. |
resultsarray
|
One entry per requested session, in request order. |
results[].accountIdstring
|
Echoed from the request. |
results[].unitIdstring
|
Echoed from the request. |
results[].verificationStatusstring
|
Echoed from the request. |
results[].interactionIdstring
|
Echoed from the request. |
results[].successboolean
|
Whether the score was computed for this item. |
results[].reasonstringoptional |
Present when success is false. One of insufficient_observations, unsupported_platform, no_user_baseline, forbidden, internalError. |
results[].resultobjectoptional |
anomaly and anomalyConfidence for this item. |
results[].observationTimestringoptional |
Timestamp of the latest observation for this session. |
Response 400
Returned without the standard envelope for a Content-Type other than application/json, or a batch outside the 1–100 range.
Response 401
Authorization information is missing, or the token is invalid. The batch endpoint authenticates the same way as the single-item endpoint.
Resources
Verification Status
verificationStatus records the end user's authentication state, decoupled from identity. Futurae never verifies it: on a query it is a filter over which observations are considered, optional except for Remote Access Tool. See Matching.
| Value | Meaning |
|---|---|
unverified |
The page or app knows of the user but they are not yet authenticated: a login page after the username is entered, or a mobile enrollment or account-recovery flow. |
verified |
There is a valid, authenticated user session: any page after login, or day-to-day use of an enrolled app. |
fraud |
A unit or interaction previously labeled verified that was subsequently confirmed fraudulent. |
Failure Reasons
When a signal returns success: false, reason carries a machine-readable explanation.
| Value | Meaning | Returned by |
|---|---|---|
insufficient_observations |
Not enough observations to compute the signal. The normal outcome for a new user, or too little data in the requested window. | all signals |
unsupported_platform |
The signal is not available for the sensor's platform. Returned only when the stored observations prove that platform. | all signals |
no_user_baseline |
There is nothing to compare against: the baseline side of a pair has no observations, or the signal compares against the user's own earlier observations and there are none. | signals that compare against a baseline |
forbidden |
The token does not authorize this item. | Remote Access Tool batch only |
internalError |
An internal failure while computing this item. | Remote Access Tool batch only |
The single-item endpoints report the cases behind forbidden and internalError as HTTP errors instead.
Supporting Signals
The two proximity signals report the individual signals that contributed to a result. Each entry has a type and a details object of uniform shape:
| Field | Description |
|---|---|
typestring
|
Name of the contributing signal, from the values below. |
details.matchedboolean
|
Whether this signal matched across the two units. |
details.matchCountintegernullable |
How many items matched, for count-based signals. null for boolean-only ones. |
The optional supportingSignal query parameter on both proximity endpoints restricts computation to a single type.
Sensor-derived
type |
matchCount |
Meaning | Source |
|---|---|---|---|
reportedIpOverlap |
null |
Both units reported an identical client IP. | Client IP |
wifiNetworkOverlap |
count | Scanned Wi-Fi networks seen by both units. | Wi-Fi scan |
connectedWifiNetworkOverlap |
null |
Both units connected to the same Wi-Fi network. | Connected Wi-Fi |
connectedNetworkDeviceOverlap |
count | Devices both units observed on their connected Wi-Fi network. | Wi-Fi network devices |
connectedBleDeviceOverlap |
count | BLE peripherals connected to both units. | BLE peripherals |
scannedBleDeviceOverlap |
count | BLE devices seen in scan results by both units. | BLE scan |
nearbyDeviceOverlap |
count | Nearby devices observed by both units. | Nearby devices |
locationOverlap |
null |
The units' latest coordinates indicate the same place. | GPS location |
Ingress-IP-derived
Derived from the IP observed at Futurae's network edge, rather than reported by the SDK.
type |
matchCount |
Meaning |
|---|---|---|
ingressIpOverlap |
null |
Both units seen from an identical ingress connecting IP. |
ingressIpCityOverlap |
null |
Ingress-derived city matched. |
ingressIpRegionOverlap |
null |
Ingress-derived region matched. |
ingressIpCountryOverlap |
null |
Ingress-derived country matched. |
ingressIpContinentOverlap |
null |
Ingress-derived continent matched. |
Geovelocity Source
One entry per location source evaluated by Get Geovelocity Signal.
| Parameter | Description |
|---|---|
locationSourcestring
|
Which source this entry evaluates. Currently only gps. |
evaluatedboolean
|
false when this source had no observation pair to score. |
anomalyboolean
|
true if maxSpeedKmh is strictly greater than thresholdKmh. |
maxSpeedKmhnumbernullable |
Highest implied travel speed among evaluated pairs, km/h to one decimal. Equal to fastestPair.speedKmh. null when no pair could be scored. |
thresholdKmhnumbernullable |
The threshold maxSpeedKmh is compared against. null when no pair could be scored. |
evaluatedPairCountinteger
|
Number of observation pairs considered. |
fastestPairobjectnullable |
The pair that produced maxSpeedKmh. null when no pair could be scored. |
Fastest pair
| Parameter | Description |
|---|---|
fromObservationTimestring
|
RFC 3339 timestamp of the earlier observation. |
toObservationTimestring
|
RFC 3339 timestamp of the later observation. |
fromUnitIdstring
|
unitId the earlier observation was recorded under. |
fromVerificationStatusstring
|
verificationStatus the earlier observation was recorded under. |
fromInteractionIdstring
|
interactionId the earlier observation was recorded under. |
toUnitIdstring
|
unitId the later observation was recorded under. |
toVerificationStatusstring
|
verificationStatus the later observation was recorded under. |
toInteractionIdstring
|
interactionId the later observation was recorded under. |
distanceKmnumber
|
Great-circle distance between the two observations, km to one decimal. |
elapsedSecondsinteger
|
Seconds between the two observations. |
speedKmhnumber
|
distanceKm ÷ (elapsedSeconds ÷ 3600), to one decimal. |
Datapoints
A datapoint is one stored observation of one measurement. Every datapoint carries the common fields below, plus a value whose shape is determined by valueType.
| Parameter | Description |
|---|---|
namestring
|
Datapoint name, e.g. geo, ingress_ip_country. |
observationTimestring
|
RFC 3339 timestamp of the observation. |
valueTypestring
|
Discriminator: number, string, boolean, geo or device. |
unitIdstring
|
unitId of the observation that reported this datapoint. |
verificationStatusstring
|
verificationStatus of that observation. |
interactionIdstring
|
interactionId of that observation. |
Value by type
Each valueType adds the fields below to the common ones.
valueType |
Fields | Example |
|---|---|---|
number |
value (number) |
"value": 22.5 |
string |
value (string) |
"value": "Budapest" |
boolean |
value (boolean) |
"value": true |
geo |
lat (number): latitudelon ( number): longitude |
"lat": 47.4979, "lon": 19.0402 |
device |
deviceName (string): name of the devicemac ( string): MAC address of the device |
"deviceName": "Office printer", "mac": "de:ad:be:ef:ff:ff" |