## TL;DR
The risk_score does not live on the PaymentIntent. It lives on the charge's outcome object, so read `latest_charge.outcome.risk_score`. The score is null until the payment is confirmed and Radar has evaluated it, and only card payments get scored. If the expanded charge still shows null, the payment probably never went through an evaluation.

```text
"risk_score" is null on stripe payment_intent despite radar enabled
```

## Use this when
- Retrieving a PaymentIntent shows no risk_score at the top level.
- You need the Radar score for a card payment from the API.
- The dashboard shows a risk level your API code cannot see.

## Not for this skill when
- The payment method is not a card. Bank debits and similar methods never get a Radar card score.
- You are debugging a Radar rule that did not fire. That is rule evaluation, not scoring.
- The null appears on a refunded or canceled intent where no charge exists.

## Steps
1. Retrieve the PaymentIntent with the charge expanded: `stripe.PaymentIntent.retrieve("pi_xxx", expand=["latest_charge"])`. Verify: the response includes a `latest_charge` object.
2. Read `latest_charge.outcome.risk_score` and `latest_charge.outcome.risk_level`. Verify: `risk_level` is one of normal, elevated, or highest.
3. Check the PaymentIntent reached post-confirmation; an unconfirmed intent has no evaluation yet. Verify: `status` reads `requires_capture` or `succeeded`.
4. Confirm the payment method is a card via `latest_charge.payment_method_details.type`. Verify: the type reads `card`.
5. Confirm Radar is enabled in the same mode you are querying. Verify: the Dashboard Radar overview shows evaluations for that mode.

## Variant phrasings
### stripe paymentintent risk score empty
Same fix, shorter phrasing.
### radar score missing from payment intent api response
Focuses on the API response shape.
### stripe outcome risk_score null on charge
Same underlying cause, charge-level phrasing.

Compatibility: Stripe API 2023-10-16 and later. Radar risk scoring applies to card payments; Radar for Fraud Teams unlocks the richer risk_insights signals.

## Why it happens
Radar evaluates at confirm time and writes the result onto the charge's outcome. The PaymentIntent never carries the score directly, so code reading a top-level `risk_score` always sees null. Intents that never reach confirmation never get evaluated.

## Edge cases / pitfalls
- In test mode, scores are simulated and some signals are absent. Do not tune production thresholds on test scores.
- A charge created with separate auth and capture still scores at auth time. Null after that points to a non-card method.
- If you use the evaluate_payment API, the score lives on the returned payment_evaluation object, which is separate from both the intent and the charge.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Rv-WrDuHK1gZAsjmqN6_nA
