Trust Signals: Signals
Your backend queries signals from the Signals API at its decision points. The querying component depends on how you use the signals: commonly a risk or fraud-detection engine, an IAM backend, or the business application backend itself.
This page explains what each signal means and how to read its result. The exact endpoints, parameters and response shapes are in the Trust Signals API Reference.
Querying a signal
At each authentication or transaction decision point, your backend calls GET https://ts-signals-public.futurae.com/api/v1/signals/<signal>, with a signals token from the retrieval client in the Authorization header. The endpoint paths below are relative to that host. How to obtain and refresh the token is in Authorization and Proxy.
Every query identifies the observations to use:
| Parameter | Required | Purpose |
|---|---|---|
serviceId | Yes | Your tenant. It must equal the service_id claim of the token. |
accountId | Yes | The user whose observations to use. Paired signals take subjectAccountId, required, and baselineAccountId, which you can omit when both sides belong to the same user. |
unitId | No, except for Remote Access Tool | Considers only observations from this application, matched exactly. Paired signals take baselineUnitId and subjectUnitId instead. |
verificationStatus | No, except for Remote Access Tool | Considers only observations with exactly this label. Requires unitId. |
interactionId | No, except for Remote Access Tool | Considers only observations whose interactionId starts with this value. Requires verificationStatus. |
sdkVersionId | No | Considers only observations from this SDK version. |
windowStart, windowEnd | No | The time window to consider. See Time windows. |
A query that supplies the identifiers out of order is rejected with 400. How the identifiers select observations is explained in How a query is scoped.
Signal availability
| Signal | Android | iOS | Browser | Observations needed |
|---|---|---|---|---|
| Latest Proximity | ✅ | ✅ | ✅ | From two SDK instances, in any combination of platforms |
| Historical Proximity | ✅ | ✅ | ✅ | From two SDK instances, in any combination of platforms |
| New Browser | — | — | ✅ | From one SDK instance |
| Geolocation | ✅ | ✅ | ✅ | From one SDK instance |
| Geovelocity | ✅ | ✅ | — | From one SDK instance |
| Active Call | ✅ | ✅ | — | From one SDK instance |
| Remote Access Tool | — | — | ✅ | From one session, plus earlier sessions of the same user |
Requesting a signal for a platform it does not support returns 200 OK with success: false.
Reading the response
Every signal endpoint returns 200 OK with the same outer shape around a signal-specific payload. Whether the signal could be computed is carried by the success field in the body, not by the HTTP status code.
| Field | Present | Description |
|---|---|---|
signalType | Always | The stable identifier of the signal type. |
success | Always | true when the signal was computed; false when it could not be. |
reason | Only when success is false | A machine-readable failure reason: insufficient_observations, unsupported_platform or no_user_baseline. |
result | Only when success is true | The computed signal value. Always a JSON object, never a bare string, boolean or array, so a signal can gain an output later without breaking your parser. |
observationTime | Only when success is true | The RFC 3339 UTC timestamp of the observation used to compute result. Latest Proximity and Historical Proximity return observationTimesByUnit instead, with one timestamp per side under the keys baselineUnitId and subjectUnitId. |
A failed signal has no opinion on the case: treat success: false separately from a result that looks normal. What each reason means, and what to check, is in Troubleshooting.
Check observationTime too. Signals are computed from stored observations, so a success: true result built on hours-old data may be too stale for a real-time decision.
Trust Signals returns per-signal, probabilistic inputs, never a single composite risk number. Combining them into a decision is your policy engine’s job, which is why each value names the proposition it expresses confidence in, rather than being called a score.
Time windows
Most signals accept an optional windowStart and windowEnd, in RFC 3339 UTC. The window may span at most 31 days. When it is omitted, it defaults to the last 31 days up to the current time.
Remote Access Tool is the exception: it takes no time window. It evaluates one session, its lookback is fixed server-side, and its baseline is determined separately, see Baseline anchoring.
Signals
Latest Proximity
Determines whether two of the user’s devices are physically co-located at a given moment, by cross-referencing the latest sensor observations from both. Returns a proximityConfidence, a value from 0 to 1 where higher means more likely co-located, and the set of supporting signals that explain it.
| Endpoint | GET /api/v1/signals/latest-proximity |
| 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 initiates authentication remotely while the legitimate user’s phone is elsewhere. A mismatch between the two devices can flag the action for step-up or block. |
Historical Proximity
Determines whether two of the user’s devices were physically near each other at any moment within a time window. Where Latest Proximity evaluates only the latest observations, this signal scans every observation in the window and returns the highest proximityConfidence reached at any point, along with the observation pair that produced it.
| Endpoint | GET /api/v1/signals/historical-proximity |
| Data sources | Same as Latest Proximity. |
| Use case 1 | Retroactive fraud investigation: determine whether two devices active during a suspicious transaction were ever co-located in the preceding period. |
| Use case 2 | New authenticator enrollment: confirm a newly enrolled device has previously been co-located with an existing trusted authenticator before granting full access. |
Two independent best matches are returned: one over sensor observations, and one over ingress-IP observations. Either may be absent when no pair of that kind could be evaluated.
New Browser
Determines whether a browser profile is new to this user, meaning it was seen in no earlier session within the time window. It compares the latest fingerprint of a subject side with the history of a baseline side, and the result classifies the browser as known or new. Because the two sides can belong to different accounts, you can score a login before the user’s identity is confirmed: collect under a temporary account ID, then pass the real user as baselineAccountId.
The matchScope parameter sets how much of the fingerprint must match: the browser name, operating system and version by default, or the full fingerprint. When the browser is new, mismatchedFields lists the fields that differed from the closest earlier observation.
| Endpoint | GET /api/v1/signals/new-browser |
| Data sources | Browser fingerprint |
| Use case | Trigger additional verification when a user authenticates from a previously unseen browser profile, which may indicate account takeover via credential theft. |
Matching cooldown
The cooldownSeconds parameter sets how far back from now the signal looks before it accepts an observation as evidence that the browser has been seen before. Observations newer than now minus cooldown are excluded from the comparison, so only fingerprints older than that cutoff count toward a known result. It defaults to 3600 seconds, one hour.
This matters in two ways:
- It ignores a session’s own resubmissions. The SDK sends the fingerprint repeatedly during a session. Without a cooldown, a brand-new browser could match its own recent submissions and come back as known. This matters only when both sides cover the same unit.
- It gives recent sessions time to be trusted. A session that happened moments ago may still turn out to be fraudulent. The cooldown holds it back from counting as trusted history, which lets you control how quickly a new browser becomes known.
Increase cooldownSeconds if your sessions stay active longer than an hour, or if you want a longer grace period before recent sessions count as trusted history.
Geolocation
Returns the best available location estimate for the device, drawing on several independent sources. Each source is returned as a separate entry, so you can apply your own resolution and confidence logic.
| Endpoint | GET /api/v1/signals/geolocation |
| Data sources | GPS (mobile only), public IP geolocation |
| Use case | Enforce country- or region-based access policies. |
The result carries one entry per data source for which at least one observation exists in the window, each holding the latest value for that source: sensor coordinates, IP-derived coordinates, and IP-derived city, region, country and continent. A source is absent when no data exists for it.
Geovelocity
Detects physically impossible travel of the user’s mobile device, by computing the speed implied by pairs of GPS observations in the window. An anomaly is flagged when that speed exceeds a physically plausible threshold. Geovelocity is available for the Mobile Sensor SDK only.
| Endpoint | GET /api/v1/signals/geovelocity |
| Data sources | GPS observations from the Mobile Sensor SDK |
| Use case | Detect credential theft or session hijacking: if the user’s phone appears in two distant locations within a short interval, such as Zurich and New York within an hour, flag the action for step-up or block it. |
The response reports the threshold the speed was compared against, along with the observation pair that produced the fastest implied speed, which makes a verdict reproducible. Its list of location sources currently holds a single GPS entry. The time window must cover both location events being compared.
Active Call
Reports whether the user’s mobile device was on an active phone call, based on the latest phone-call state observation in the window.
| Endpoint | GET /api/v1/signals/active-call |
| Data sources | Phone-call state |
| Use case | Detect vishing and social-engineering attacks: during a transaction confirmation or an authentication approval, an active call is a strong indicator that an attacker may be guiding the user into approving a fraudulent operation. |
Remote Access Tool
Reports how likely it is that the browser is being operated through remote desktop software rather than directly by a person, as an anomalyConfidence from 0 to 1, where higher means more suspicious, alongside an anomaly boolean. The classifier works on a combination of browser fingerprint characteristics, keyboard dynamics and mouse movement patterns.
| Endpoint | GET /api/v1/signals/remote-access-tool for one session, POST /api/v1/signals/remote-access-tool for a batch |
| Data sources | Browser fingerprint, keyboard dynamics, mouse movement patterns |
| Use case | Detect remote-access fraud: an attacker controlling the victim’s browser session with remote-control tooling such as TeamViewer. |
A session is defined by the combination of unitId, verificationStatus and interactionId. This is the one signal that matches interactionId exactly rather than as a prefix. unitId, verificationStatus and interactionId are all required, so the values you supply address one session and no other. The single endpoint evaluates one session per call; the batch endpoint evaluates several in one call.
Preconditions
The classifier evaluates a session only when all of these hold. Otherwise the signal returns success: false with the reason shown:
| Precondition | reason when it fails |
|---|---|
| The session comes from a desktop browser and operating system combination that Futurae maintains a model for. | unsupported_platform |
| The session contains enough mouse-movement and key-press events to characterize it. | insufficient_observations |
| Enough earlier sessions exist for the same user and platform, containing both mouse-movement and key-press events. | no_user_baseline |
The Browser SDK must also collect the mouse_move, key_press and fingerprint features. If you restrict features below those three, the signal cannot be computed.
These reasons mean the signal has no opinion on the session. Treat them separately from a low anomalyConfidence, which is a positive statement that the session looks normal. The exact conditions are listed in the Trust Signals API Reference.
Baseline anchoring
Each session is evaluated against a user profile: a per-user, per-platform baseline built from that user’s earlier sessions.
The default, baselineScope=interaction_anchored, anchors the baseline to the moment the evaluated session took place. Re-querying a historical session at a later date therefore returns the same anomalyConfidence, which is usually what you want for an investigation.
Pass baselineScope=full_history to build the baseline from the user’s complete history up to the current moment instead. This is useful when you retroactively assess an old session, at the cost of that stability: re-querying the same session later can then return a different value as more history accumulates.
Supporting signal types
The two proximity signals report the individual checks that contributed to the proximityConfidence. Each entry carries a type identifier and a details object.
details has one shape for every type: { "matched": boolean, "matchCount": integer|null }. matched says whether the two units agreed on that check. matchCount gives how many items overlapped where counting is meaningful, such as shared Wi-Fi networks, and is null for checks that are simply true or false.
Sensor-derived
type | Match definition | matchCount |
|---|---|---|
reportedIpOverlap | Both units reported an identical client IP. | — |
wifiNetworkOverlap | Wi-Fi networks seen in scans by both units. | Scanned networks in common |
connectedWifiNetworkOverlap | Both units are connected to the same Wi-Fi network. | — |
connectedNetworkDeviceOverlap | Devices both units observed on their connected Wi-Fi network. | Devices in common |
connectedBleDeviceOverlap | Bonded or connected BLE peripherals observed by both units. | Peripherals in common |
scannedBleDeviceOverlap | BLE devices seen in scan results by both units, not necessarily bonded. | Devices in common |
nearbyDeviceOverlap | Nearby devices observed by both units. | Devices in common |
locationOverlap | The two units' latest coordinates fall within a neighborhood-scale tolerance. | — |
Ingress-IP-derived
type | Match definition |
|---|---|
ingressIpOverlap | Both units were seen from an identical ingress connecting IP. |
ingressIpCityOverlap | The ingress-derived city matched. |
ingressIpRegionOverlap | The ingress-derived region matched. |
ingressIpCountryOverlap | The ingress-derived country matched. |
ingressIpContinentOverlap | The ingress-derived continent matched. |
Reported versus ingress IP. reportedIpOverlap compares the IP address the SDK itself reported. The ingressIp* family compares what Futurae observed at the network edge. They can disagree, and that disagreement is itself informative.
In Historical Proximity the two evaluation paths are kept separate: only sensor-derived signals appear in the sensor best match, and only ingress-IP signals in the ingress best match.
The optional supportingSignal parameter on both proximity endpoints restricts computation to a single supporting signal type.