Skip to main content

Attestation API

Generate verifiable proof about a vehicle's data.

Overview

The DIMO Attestation API provides cryptographic, on-chain attestations for vehicle data and identity verification. This API enables developers to generate verifiable attestations.

Base URL

https://attestation-api.dimo.zone

Endpoints

Create a vehicle VIN attestation

Generates the VIN attestation for a given vehicle if it has never been created, or if it has expired. If an unexpired attestation is found, returns the attestation. After you've obtained the rawVC from the response, you can use it to perform queries on the Telemetry API, such as getting the VIN of a vehicle.

Parameters

vehicleJwtstringRequired
A valid JWT token that represents the vehicle's authentication credentials. This token must be obtained through the DIMO authentication flow.
tokenIdintegerRequired
The unique identifier of the vehicle token. This is provided in the URL path.
POST/v2/attestation/vin/:tokenId
const vinVc = await dimo.attestation.createVinVc({
vehicleJwt: "eyJhbGc...ILlujqw",
tokenId: 123456
})
Response
{
"vcUrl": "https://telemetry-api.dimo.zone/query",
"vcQuery": "query {vinVCLatest(tokenId: <TOKEN_ID>) {rawVC}}",
"message": "VC generated successfully. Retrieve using the provided GQL URL and query parameter."
}

Create a vehicle odometer statement VC

Generates the odometer statement attestation for a given vehicle if it has never been created, or if it has expired. If an unexpired attestation is found, returns the attestation. After you've obtained the rawVC from the response, you can use it to perform queries on the Telemetry API, such as getting the odometer of a vehicle.

Parameters

vehicleJwtstringRequired
A valid JWT token that represents the vehicle's authentication credentials. This token must be obtained through the DIMO authentication flow.
tokenIdintegerRequired
The unique identifier of the vehicle token. This is provided in the URL path.
timestamptimeOptional
Optional timestamp.
POST/v2/attestation/odometer-statement/:tokenId
const vinVc = await dimo.attestation.createOdometerStatementVC({
vehicleJwt: "eyJhbGc...ILlujqw",
tokenId: 123456,
timestamp: '2023-01-01T00:00:00Z' // Optional
})
Response
{
"message": "VC generated successfully, retrieve using the provided telemetry-api."
}

Create a vehicle health attestation

Generates the vehicle health attestation for a given vehicle if it has never been created, or if it has expired. If an unexpired attestation is found, returns the attestation. After you've obtained the rawVC from the response, you can use it to perform queries on the Telemetry API, such as getting the health status of a vehicle.

Parameters

vehicleJwtstringRequired
A valid JWT token that represents the vehicle's authentication credentials. This token must be obtained through the DIMO authentication flow.
tokenIdintegerRequired
The unique identifier of the vehicle token. This is provided in the URL path.
startTimetimeRequired
The start time of the vehicle health report.
endTimetimeRequired
The end time of the vehicle health report.
POST/v2/attestation/vehicle-health/:tokenId
const vinVc = await dimo.attestation.createVehicleHealthVc({
vehicleJwt: "eyJhbGc...ILlujqw",
tokenId: 123456,
startTime: '2023-01-01T00:00:00Z',
endTime: '2023-01-15T00:00:00Z'
})
Response
{
"message": "VC generated successfully, retrieve using the provided telemetry-api."
}

Create a vehicle position attestation

Generates the vehicle position attestation for a given vehicle if it has never been created, or if it has expired. If an unexpired attestation is found, returns the attestation. After you've obtained the rawVC from the response, you can use it to perform queries on the Telemetry API, such as getting the position of a vehicle.

Parameters

vehicleJwtstringRequired
A valid JWT token that represents the vehicle's authentication credentials. This token must be obtained through the DIMO authentication flow.
tokenIdintegerRequired
The unique identifier of the vehicle token. This is provided in the URL path.
timestamptimeRequired
The time of the vehicle position.
POST/v2/attestation/vehicle-position/:tokenId
const vinVc = await dimo.attestation.createVehiclePositionVc({
vehicleJwt: "eyJhbGc...ILlujqw",
tokenId: 123456,
timestamp: '2023-01-01T00:00:00Z'
})
Response
{
"message": "VC generated successfully, retrieve using the provided telemetry-api."
}

Document Insertion

Insurance cards, registrations, service invoices, titles, inspections, driver licenses, and other vehicle paperwork live on DIMO as signed CloudEvents. You post them to the DIMO Ingest Server (DIS) attestation endpoint, and you pull them back out through the Fetch API. For large files, the Fetch API returns a presigned S3 URL on dataUrl instead of inlining the bytes.

DIS accepts two CloudEvent type families on the attestation endpoint in addition to `dimo.attestation`:

CloudEvent types

dimo.raw.*
Unparsed source artifact. Typically the raw bytes of an uploaded file (PDF, JPEG, PNG). The data payload is the file content, usually base64-encoded with an explicit datacontenttype.
dimo.document.*
Parsed/structured form of a document. The data payload is JSON with the extracted fields. Use raweventid in the header to link back to the dimo.raw.* event the parse came from.
Sign each event with `source`. That can be an EOA private key, or an ERC-1271 contract like a developer license. Headers follow the same conventions as `dimo.attestation`; see the [DIS attestation header reference](https://github.com/DIMO-Network/dis#attestation-cloud-event-header-descriptions) for the full field list. Large documents land in S3 as individual objects rather than getting inlined into the index. When you query them back, the Fetch API hands you a presigned `dataUrl` rather than `data` or `dataBase64`.

Supported dimo.document.* subtypes

dimo.document.vehicle.insurance
Insurance policies and ID cards.
dimo.document.vehicle.registration
Government vehicle registrations.
dimo.document.vehicle.title
Vehicle titles.
dimo.document.vehicle.service.invoice
Service / maintenance receipts.
dimo.document.vehicle.inspection
Safety / emissions inspection reports.
dimo.document.vehicle.finance
Loan statements, lien releases, payment notices.
dimo.document.vehicle.regulatory.other
Catchall for tax receipts, traffic violations, fees.
dimo.document.driver.license
Driver licenses.
dimo.document.unknown
Returned by the Extract API when classification fails. Useful as a placeholder; not normally posted directly.

Base URL

https://attest.dimo.zone

Endpoints

POST/
curl -X POST "https://attest.dimo.zone/" \
-H "Authorization: Bearer <DEVELOPER_JWT>" \
-H "Content-Type: application/json" \
-d '{
"id": "unique-identifier",
"source": "0xConnectionLicenseAddress",
"producer": "did:ethr:137:0xSignerAddress",
"specversion": "1.0",
"subject": "did:erc721:137:0xbA5738a18d83D41847dfFbDC6101d37C69c9B0cF:42",
"time": "2026-05-22T12:00:00Z",
"type": "dimo.document.vehicle.insurance",
"datacontenttype": "application/json",
"raweventid": "ksuid-of-the-dimo.raw.insurance-event",
"signature": "0x...",
"data": {
"policyNumber": "SF-12345678",
"insurerName": "State Farm",
"insuredAddress": "123 Main St, Denver, CO 80202",
"vin": "1GGCM82633A123456",
"state": "CO",
"coverageType": "full coverage",
"effectiveDate": "2025-01-01",
"expirationDate": "2025-07-01"
}
}'

Retrieving stored documents

Documents come back through the Fetch API like any other CloudEvent. The one thing to remember: ask for dataUrl. The raw file is served as a presigned S3 link, not inlined into the response, so if you skip dataUrl you will not get the bytes.

query LatestInsurance {
latestCloudEvent(
did: "did:erc721:137:0xbA5738a18d83D41847dfFbDC6101d37C69c9B0cF:42",
filter: { type: "dimo.document.vehicle.insurance" }
) {
header { id type time raweventid }
data # parsed fields, when present
dataUrl # presigned S3 link to the raw file
}
}

To see which document types exist for a vehicle before querying, hit availableCloudEventTypes. To pull several subtypes in one round-trip, filter cloudEvents by types: ["dimo.document.vehicle.insurance", "dimo.document.vehicle.registration", ...].

Extract API

The Extract API is the parser. You hand it a vehicle document; it tells you what the document is and what fields it contains. That is the whole job. It does not store the file, it does not sign a CloudEvent, and it does not post anything to DIS. If you already have your own storage and lifecycle pipeline and just need classification plus field extraction, this is the right service to call. If you want the full upload + storage + attestation flow handled for you, go through the orchestration layer in the DIMO mobile backend instead.

Upload a PDF or image (JPEG, PNG, GIF, WebP, TIFF, BMP, up to 20 MB). You get back the inferred CloudEvent `type` and the extracted fields. Auth is a developer-license JWT in the standard `Authorization: Bearer` header.

Request (multipart/form-data)

filefileRequired
The document to extract. PDF or image. Max 20 MB.
category_hintstringOptional
Narrows the spec set Claude considers. Accepted values: service, insurance, regulatory, ownership, driver. Unknown values are ignored.

Response

typeString
The classified CloudEvent type. One of the dimo.document.* subtypes listed above, or dimo.document.unknown when the document does not match any spec.
data.fieldsobject
Key/value map of extracted fields. Shape depends on the document type.

category_hint values

service
Considers only vehicle.service.invoice.
insurance
Considers only vehicle.insurance.
regulatory
Considers vehicle.registration, vehicle.inspection, vehicle.regulatory.other, driver.license.
ownership
Considers vehicle.title, vehicle.finance, vehicle.registration.
driver
Considers only driver.license.
If you pass an unknown value or skip the field entirely, the service quietly falls back to the full spec set. There is a small efficiency reason to do this on purpose: the un-hinted path keeps the prompt cache warm, so requests run a little faster. When in doubt, leave `category_hint` off.

Base URL

https://extract.dimo.zone

Endpoints

POST/extract
curl -X POST "https://extract.dimo.zone/extract" \
-H "Authorization: Bearer <DEVELOPER_JWT>" \
-F category_hint=regulatory
Response
{
"type": "dimo.document.vehicle.registration",
"data": {
"fields": {
"vin": "1GGCM82633A123456",
"plateNumber": "ABC-1234",
"registrationLocation": "California",
"issuingAuthority": "California DMV",
"expirationDate": "2027-04-30",
"ownerName": "Jane Doe"
}
}
}
Full document lifecycle

Extract only parses. If you want the whole document round-trip — store the file, parse it, link the parse back to the raw upload, query both later — it looks like this:

  1. POST a dimo.raw.<subtype> CloudEvent to https://attest.dimo.zone with the file as the signed data payload. Save the event id; it becomes the raweventid for the parse.
  2. POST the same file to https://extract.dimo.zone/extract. You get back a type and data.fields.
  3. POST a second CloudEvent to https://attest.dimo.zone using the type Extract returned (e.g. dimo.document.vehicle.insurance). Put the extracted fields in data and the raw event id from step 1 in raweventid.
  4. Query both events back through the Fetch API. The raw file comes back as a presigned dataUrl.

Document field schemas

Every dimo.document.* type carries a defined set of fields under data.fields. The Extract API returns this shape, and you post the same shape when you store a dimo.document.* event. Fields are best-effort: anything the source document does not contain comes back null, so a real document often has fewer keys than shown. Pick a type to see its fields.

{
"type": "dimo.document.vehicle.insurance",
"data": {
"fields": {
"policyNumber": "SF-12345678",
"insurerName": "State Farm",
"naicNumber": "25178",
"insuredAddress": "123 Main St, Denver, CO 80202",
"ownerName": "Jane Doe",
"vin": "1GGCM82633A123456",
"plateNumber": "ABC-1234",
"state": "CO",
"coverageType": "full coverage",
"effectiveDate": "2025-01-01",
"expirationDate": "2025-07-01",
"premium": 842.5,
"currency": "USD",
"additionalDrivers": "John Doe",
"additionalVehicles": [
{
"vin": "2HGED36426H123789",
"plateNumber": "XYZ-9988",
"description": "2019 GMC Yukon"
}
]
}
}
}

dimo.document.unknown has no defined fields. The Extract API returns it when a document matches no spec; treat it as an unclassified placeholder rather than a schema.