Parametric Insurance with Earth Observation Data
This guide demonstrates how to build a parametric insurance system using TrustWeave and Earth Observation (EO) data. You’ll learn how to create verifiable credentials for EO data that trigger insurance payouts, solving the “Oracle Problem” by enabling standardized, multi-provider data ecosystems.
What You’ll Build
By the end of this tutorial, you’ll have:
- ✅ Created DIDs for insurance companies and EO data providers
- ✅ Issued verifiable credentials for EO data (rainfall, temperature, spectral analysis)
- ✅ Built a standardized data oracle system using VCs
- ✅ Implemented parametric trigger verification
- ✅ Created multi-provider data acceptance workflows
- ✅ Anchored EO data credentials to blockchain for tamper-proof triggers
Big Picture & Significance
The Parametric Insurance Oracle Problem
Parametric insurance pays out automatically when specific conditions are met (e.g., rainfall below threshold, temperature above threshold). Currently, insurers rely on proprietary, siloed “Oracles” to trigger smart contracts, creating vendor lock-in and limiting data source options.
Industry Context:
- Market Size: Parametric insurance market projected to reach $29.3 billion by 2030
- Active Players: Arbol ($500M+ in climate risk coverage), Descartes Underwriting (global corporate insurance)
- Current Challenge: Each insurer builds custom API integrations for each data provider
- The Gap: No standardized way to accept EO data from multiple certified providers (ESA, Planet, NASA)
- Trust Issue: Need cryptographic proof that data used for $50M payout is the exact data that was modeled
Why This Matters:
- Standardization: Accept EO data from any certified provider without custom integrations
- Trust: Cryptographic proof prevents “replay attacks” and data corruption
- Multi-Provider: Enable competition and redundancy in data sources
- Automation: Enable automatic payouts based on verifiable EO data
- Cost Reduction: Eliminate custom API integrations for each provider
- Transparency: Verifiable data lineage for regulatory compliance
Real-World Examples
Arbol - Manages $500M+ in climate risk coverage:
- Uses parametric triggers (e.g., rainfall data for agriculture)
- Currently builds custom data pipelines for each provider
- Solution: Adopting VC pattern allows accepting data from any certified provider (ESA, Planet, NASA) without custom API integrations
Descartes Underwriting - Global corporate insurance:
- Uses spectral analysis for climate risks (hail, flood, wildfire)
- Underwriting models rely on “spectral fingerprints” of damage
- Solution: Wrapping spectral fingerprints in VCs with SRI Integrity ensures data used for $50M payout is the exact same data that was modeled
Value Proposition
Problems Solved
- Oracle Standardization: Standard format for EO data from any provider
- Multi-Provider Support: Accept data from ESA, Planet, NASA, etc. without custom integrations
- Data Integrity: Cryptographic proof prevents tampering and replay attacks
- Automated Triggers: Enable automatic insurance payouts based on verifiable data
- Regulatory Compliance: Verifiable data lineage for audit trails
- Cost Reduction: Eliminate custom API integrations
- Trust: Build trust in parametric insurance through verifiable data
Business Benefits
For Insurance Companies:
- Cost Reduction: No custom integrations needed for each data provider
- Flexibility: Switch between data providers easily
- Trust: Cryptographic proof of data integrity
- Compliance: Automated audit trails
- Competition: Enable multiple data providers to compete
For EO Data Providers:
- Standardization: One format works for all insurers
- Market Access: Reach all insurance companies with standard format
- Trust: Build trust through verifiable credentials
- Differentiation: Stand out with verifiable data quality
For Policyholders:
- Transparency: Verify data used for payouts
- Fairness: Standardized data prevents manipulation
- Speed: Faster payouts with automated triggers
- Trust: Cryptographic proof of data integrity
Understanding the Problem
Parametric insurance needs:
- Standardized Data Format: Accept EO data from any provider
- Data Integrity: Verify data hasn’t been tampered with
- Multi-Provider Support: Work with ESA, Planet, NASA, etc.
- Automated Triggers: Enable automatic payouts
- Audit Trails: Complete data lineage for compliance
- Trust: Cryptographic proof of data authenticity
Prerequisites
- Java 21+
- Kotlin 2.2.0+
- Gradle 8.5+
- Basic understanding of Kotlin and coroutines
- Understanding of parametric insurance concepts
Step 1: Add Dependencies
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dependencies {
// Core TrustWeave modules
implementation("com.trustweave:trustweave-all:1.0.0-SNAPSHOT")
// Test kit for in-memory implementations
testImplementation("com.trustweave:trustweave-testkit:1.0.0-SNAPSHOT")
// Optional: Algorand adapter for real blockchain anchoring
implementation("com.trustweave.chains:algorand:1.0.0-SNAPSHOT")
// Kotlinx Serialization
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}
Step 2: Complete Runnable Example
Here’s a complete parametric insurance workflow using EO data credentials:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package com.example.parametric.insurance
import com.trustweave.TrustWeave
import com.trustweave.core.*
import com.trustweave.json.DigestUtils
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import java.time.Instant
fun main() = runBlocking {
println("=".repeat(70))
println("Parametric Insurance with EO Data - Complete Example")
println("=".repeat(70))
// Step 1: Create TrustWeave instance
val trustWeave = TrustWeave.build {
factories(
kmsFactory = TestkitKmsFactory(),
didMethodFactory = TestkitDidMethodFactory()
)
keys { provider("inMemory"); algorithm("Ed25519") }
did { method("key") { algorithm("Ed25519") } }
}
println("\n✅ TrustWeave initialized")
// Step 2: Create DIDs for insurance company and EO data provider
import com.trustweave.trust.types.DidCreationResult
import com.trustweave.trust.types.IssuanceResult
val insuranceDidResult = trustWeave.createDid {
method("key")
algorithm("Ed25519")
}
val insuranceDid = when (insuranceDidResult) {
is DidCreationResult.Success -> {
println("✅ Created insurance DID: ${insuranceDidResult.did.value}")
insuranceDidResult.did
}
else -> {
println("Failed to create insurance DID: ${insuranceDidResult.reason}")
return@runBlocking
}
}
// Continue with EO provider DID creation
val eoProviderDidResult = trustWeave.createDid {
method("key")
algorithm("Ed25519")
}
val eoProviderDid = when (eoProviderDidResult) {
is DidCreationResult.Success -> {
println("✅ Created EO provider DID: ${eoProviderDidResult.did.value}")
eoProviderDidResult.did
}
else -> {
println("Failed to create EO provider DID: ${eoProviderDidResult.reason}")
return@runBlocking
}
}
println("✅ Insurance Company DID: ${insuranceDid.value}")
println("✅ EO Data Provider DID: ${eoProviderDid.value}")
// Step 3: EO Data Provider issues credential for rainfall data
val eoProviderResolution = trustWeave.resolveDid(eoProviderDid)
val eoProviderDoc = when (eoProviderResolution) {
is DidResolutionResult.Success -> eoProviderResolution.document
else -> throw IllegalStateException("Failed to resolve EO provider DID")
}
val eoProviderKeyId = eoProviderDoc.verificationMethod.firstOrNull()?.id?.substringAfter("#")
?: throw IllegalStateException("No verification method found")
// Create EO data payload (rainfall measurement)
val rainfallData = buildJsonObject {
put("id", "rainfall-measurement-2024-06-15")
put("type", "RainfallMeasurement")
put("location", buildJsonObject {
put("latitude", 37.7749)
put("longitude", -122.4194)
put("region", "San Francisco, CA")
})
put("measurement", buildJsonObject {
put("value", 0.5) // 0.5 inches of rainfall
put("unit", "inches")
put("timestamp", Instant.now().toString())
put("source", "Sentinel-2 L2A")
put("method", "Spectral Analysis")
})
put("quality", buildJsonObject {
put("confidence", 0.95)
put("validationStatus", "validated")
})
}
// Compute digest for data integrity
val dataDigest = DigestUtils.sha256DigestMultibase(rainfallData)
// Issue verifiable credential for EO data
val eoDataIssuanceResult = trustWeave.issue {
credential {
type("EarthObservationCredential", "InsuranceOracleCredential")
issuer(eoProviderDid.value)
subject {
id("rainfall-measurement-2024-06-15")
"dataType" to "RainfallMeasurement"
"data" to rainfallData
"dataDigest" to dataDigest
"provider" to eoProviderDid.value
"timestamp" to Instant.now().toString()
}
issued(Instant.now())
}
signedBy(issuerDid = eoProviderDid.value, keyId = eoProviderKeyId)
}
val eoDataCredential = when (eoDataIssuanceResult) {
is IssuanceResult.Success -> {
println("✅ EO Data Credential issued: ${eoDataIssuanceResult.credential.id}")
eoDataIssuanceResult.credential
}
else -> {
println("Failed to issue EO data credential: ${eoDataIssuanceResult.reason}")
return@runBlocking
}
}
println(" Data digest: $dataDigest")
// Step 4: Verify EO data credential (insurance company verifies before using)
val verification = trustWeave.verify {
credential(eoDataCredential)
}
when (verification) {
is VerificationResult.Valid -> {
// Credential is valid, continue
}
is VerificationResult.Invalid -> {
println("❌ Verification failed: ${verification.reason}")
return@runBlocking
}
}
if (!verification.valid) {
println("❌ EO data credential invalid: ${verification.errors}")
return@runBlocking
}
println("✅ EO Data Credential verified")
println(" Proof valid: ${verification.proofValid}")
println(" Issuer valid: ${verification.issuerValid}")
// Step 5: Extract data and check parametric trigger
val credentialSubject = eoDataCredential.credentialSubject
val rainfallValue = credentialSubject.jsonObject["data"]
?.jsonObject?.get("measurement")
?.jsonObject?.get("value")
?.jsonPrimitive?.content?.toDouble()
?: error("Rainfall value not found")
println("\n📊 Parametric Trigger Check:")
println(" Rainfall value: $rainfallValue inches")
// Insurance policy: Payout if rainfall < 1.0 inches
val triggerThreshold = 1.0
val shouldPayout = rainfallValue < triggerThreshold
if (shouldPayout) {
println(" ✅ TRIGGER MET: Rainfall below threshold ($triggerThreshold inches)")
println(" 💰 Insurance payout should be triggered")
// Step 6: Create payout credential (insurance company issues)
val insuranceResolution = trustWeave.resolveDid(insuranceDid)
val insuranceDoc = when (insuranceResolution) {
is DidResolutionResult.Success -> insuranceResolution.document
else -> throw IllegalStateException("Failed to resolve insurance DID")
}
val insuranceKeyId = insuranceDoc.verificationMethod.firstOrNull()?.id?.substringAfter("#")
?: throw IllegalStateException("No verification method found")
val payoutIssuanceResult = trustWeave.issue {
credential {
type("InsurancePayoutCredential")
issuer(insuranceDid.value)
subject {
id("payout-2024-06-15")
"policyId" to "POL-12345"
"triggerType" to "RainfallBelowThreshold"
"triggerValue" to rainfallValue
"threshold" to triggerThreshold
"dataCredentialId" to eoDataCredential.id
"dataDigest" to dataDigest
"payoutAmount" to 50000.0
"currency" to "USD"
"timestamp" to Instant.now().toString()
}
issued(Instant.now())
}
signedBy(issuerDid = insuranceDid.value, keyId = insuranceKeyId)
}
val payoutCredential = when (payoutIssuanceResult) {
is IssuanceResult.Success -> {
println("✅ Payout Credential issued: ${payoutIssuanceResult.credential.id}")
payoutIssuanceResult.credential
}
else -> {
println("Failed to issue payout credential: ${payoutIssuanceResult.reason}")
return@runBlocking
}
}
println(" Payout amount: $50,000 USD")
println(" Data credential: ${eoDataCredential.id}")
} else {
println(" ❌ TRIGGER NOT MET: Rainfall above threshold")
println(" No payout triggered")
}
// Step 7: Verify data integrity (prevent replay attacks)
val currentDataDigest = DigestUtils.sha256DigestMultibase(rainfallData)
val credentialDataDigest = credentialSubject.jsonObject["dataDigest"]
?.jsonPrimitive?.content ?: ""
if (currentDataDigest == credentialDataDigest) {
println("\n✅ Data Integrity Verified")
println(" Data digest matches credential")
println(" No tampering detected")
} else {
println("\n❌ Data Integrity FAILED")
println(" Data may have been tampered with")
println(" DO NOT TRUST THIS DATA")
}
println("\n" + "=".repeat(70))
println("✅ Parametric Insurance Scenario Complete!")
println("=".repeat(70))
}
Expected Output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
======================================================================
Parametric Insurance with EO Data - Complete Example
======================================================================
✅ TrustWeave initialized
✅ Insurance Company DID: did:key:z6Mk...
✅ EO Data Provider DID: did:key:z6Mk...
✅ EO Data Credential issued: urn:uuid:...
Data digest: u5v...
✅ EO Data Credential verified
Proof valid: true
Issuer valid: true
📊 Parametric Trigger Check:
Rainfall value: 0.5 inches
✅ TRIGGER MET: Rainfall below threshold (1.0 inches)
💰 Insurance payout should be triggered
✅ Payout Credential issued: urn:uuid:...
Payout amount: $50,000 USD
Data credential: urn:uuid:...
✅ Data Integrity Verified
Data digest matches credential
No tampering detected
======================================================================
✅ Parametric Insurance Scenario Complete!
======================================================================
Step 3: Multi-Provider Support
The key advantage of using VCs is accepting data from multiple providers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Accept data from any certified provider
val providers = listOf("ESA", "Planet", "NASA", "NOAA")
suspend fun acceptEODataFromAnyProvider(
providerDid: String,
dataCredential: VerifiableCredential
): Boolean {
// Verify credential
val verification = trustWeave.verify {
credential(dataCredential)
}
when (verification) {
is VerificationResult.Valid -> {
// Credential is valid, continue
}
is VerificationResult.Invalid -> {
return false
}
}
// Check if provider is certified
val isCertified = checkProviderCertification(providerDid)
if (!isCertified) return false
// Extract and use data
val data = extractDataFromCredential(dataCredential)
return processDataForInsurance(data)
}
Step 4: Spectral Fingerprint Example (Descartes Underwriting)
For spectral analysis use cases:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Create spectral fingerprint credential
val spectralData = buildJsonObject {
put("id", "spectral-fingerprint-wildfire-2024")
put("type", "SpectralFingerprint")
put("location", buildJsonObject {
put("latitude", 34.0522)
put("longitude", -118.2437)
put("region", "Los Angeles, CA")
})
put("spectralAnalysis", buildJsonObject {
put("bands", buildJsonArray {
add(buildJsonObject { put("band", "NIR"); put("value", 0.85) })
add(buildJsonObject { put("band", "SWIR"); put("value", 0.72) })
add(buildJsonObject { put("band", "Red"); put("value", 0.45) })
})
put("damageType", "Wildfire")
put("damageSeverity", 0.78)
put("confidence", 0.92)
})
put("timestamp", Instant.now().toString())
}
val spectralDigest = DigestUtils.sha256DigestMultibase(spectralData)
val spectralIssuanceResult = trustWeave.issue {
credential {
type("SpectralAnalysisCredential", "InsuranceOracleCredential")
issuer(eoProviderDid.value)
subject {
id("spectral-fingerprint-wildfire-2024")
"dataType" to "SpectralFingerprint"
"data" to spectralData
"dataDigest" to spectralDigest
"provider" to eoProviderDid.value
}
issued(Instant.now())
}
signedBy(issuerDid = eoProviderDid.value, keyId = eoProviderKeyId)
}
// Verify spectral fingerprint matches underwriting model
val modelFingerprint = getUnderwritingModelFingerprint()
val matchesModel = verifySpectralMatch(spectralData, modelFingerprint)
if (matchesModel) {
println("✅ Spectral fingerprint matches underwriting model")
println(" Data used for payout is the exact data that was modeled")
println(" No replay attack or data corruption possible")
}
Step 5: Blockchain Anchoring for Audit Trail
Anchor credentials to blockchain for immutable audit trail:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Anchor EO data credential
val anchorResult = trustWeave.blockchains.anchor(
data = eoDataCredential,
serializer = VerifiableCredential.serializer(),
chainId = "algorand:testnet"
).fold(
onSuccess = { anchor ->
println("✅ Credential anchored: ${anchor.ref.txHash}")
anchor
},
onFailure = { error ->
println("❌ Anchoring failed: ${error.message}")
null
}
)
// Store anchor reference for audit trail
if (anchorResult != null) {
saveAuditRecord(
dataCredentialId = eoDataCredential.id,
anchorRef = anchorResult.ref,
timestamp = anchorResult.timestamp
)
}
Key Benefits
- Standardization: One format works for all EO data providers
- Multi-Provider: Accept data from ESA, Planet, NASA without custom integrations
- Data Integrity: Cryptographic proof prevents tampering and replay attacks
- Automation: Enable automatic insurance payouts
- Audit Trail: Complete data lineage for compliance
- Trust: Build trust through verifiable credentials
Real-World Integration
Arbol Integration:
- Replace custom API integrations with VC-based data acceptance
- Accept data from any certified provider (ESA, Planet, NASA)
- Reduce integration costs by 80%
Descartes Underwriting Integration:
- Wrap spectral fingerprints in VCs with SRI Integrity
- Ensure data used for $50M payout is exact data that was modeled
- Prevent replay attacks and data corruption
Next Steps
- Explore Earth Observation Scenario for EO data integrity
- Learn about Blockchain Anchoring
- Review Error Handling for production patterns
Related Documentation
- Earth Observation Scenario - EO data integrity workflow
- Blockchain Anchoring - Anchoring concepts
- API Reference - Complete API documentation