---
title: "actor.approval-answer@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/actor.approval-answer"
updated: null
---

# actor.approval-answer@1 · OpenVibe.Services

HTML: [actor.approval-answer@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/actor.approval-answer)

# ActorApprovalAnswer `actor.approval-answer@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: actor
- Visibility: public
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/actor/approval-answer.v1.json`](/docs/contracts/actor.approval-answer.json)

actor.approval-answer@1: the person's answer to a device approval (plan HO12, the phone as the agent's eyes and hands). The agent asked for the phone's camera or its location, the person did the thing themselves after reading why, and this document carries the result back to the step as untrusted input, never as an instruction. DECISION is "answer"; declining an approval stays the ordinary denial and is not this document. Exactly one of PHOTO and LOCATION is present. PHOTO is a private Media object the person took in the system camera (JPEG, PNG or WebP, at most 10 MB, EXIF stripped by Actor): a picture of the world, not a secret, a token or a URL. LOCATION is shared once, after the person allowed it: LAT is -90 to 90, LNG -180 to 180 and ACCURACY\_M is 0 to 100000 metres. PRECISE is true only when the step asked for precise and the person allowed it; when it is false the share is coarse and LAT and LNG carry at most two decimals (about a kilometre). JSON Schema cannot count decimal places, so the two-decimal rule lives in the description, is enforced by Actor and is checked by this repository's suite.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `decision` | const | yes | The only decision this document carries: the person answered the ask. A decline is the approval's ordinary denial, not a data-carrying answer. | - `= "answer"` |
| `photo` | object |  | The photo the person took in the system camera after reading why. It is stored as a private Media object in Actor's tenant, and the step reaches it through a short-lived signed URL; this document carries only the object's id. | - `no other fields` |
| `photo.media_id` | string | yes | The private Media object holding the photo (media.object@1's id: med\_<ULID>). | - `pattern ^med_[0-9A-HJKMNP-TV-Z]{26}$` |
| `location` | object |  | The place the person shared once. When PRECISE is false, LAT and LNG carry at most two decimals (about a kilometre); JSON Schema cannot count decimal places, so Actor enforces the rounding and the repository's suite holds it. A precise location is shared only when the step asked for it and the person allowed it. | - `no other fields` |
| `location.lat` | number | yes | Latitude in degrees, -90 to 90. | - `minimum -90`<br>- `maximum 90` |
| `location.lng` | number | yes | Longitude in degrees, -180 to 180. | - `minimum -180`<br>- `maximum 180` |
| `location.accuracy_m` | number | yes | The device's accuracy radius in metres, 0 to 100000. | - `minimum 0`<br>- `maximum 100000` |
| `location.precise` | boolean | yes | True only when the step asked for a precise location and the person allowed it; false for a one-time coarse share (LAT and LNG at most two decimals). |  |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: location-coarse

~~~~
{
  "decision": "answer",
  "location": {
    "lat": 52.31,
    "lng": 4.76,
    "accuracy_m": 1200,
    "precise": false
  }
}
~~~~

Valid: location-precise

~~~~
{
  "decision": "answer",
  "location": {
    "lat": 52.367612,
    "lng": 4.904123,
    "accuracy_m": 8,
    "precise": true
  }
}
~~~~

Valid: photo

~~~~
{
  "decision": "answer",
  "photo": {
    "media_id": "med_01JAB2C3D4E5F6G7H8J9K0MNPQ"
  }
}
~~~~

Rejected: coarse-four-decimals

~~~~
{
  "decision": "answer",
  "location": {
    "lat": 52.3676,
    "lng": 4.9041,
    "accuracy_m": 1200,
    "precise": false
  }
}
~~~~

Rejected: extra-field

~~~~
{
  "decision": "answer",
  "photo": {
    "media_id": "med_01JAB2C3D4E5F6G7H8J9K0MNPQ"
  },
  "note": "an extra field is never part of an answer"
}
~~~~

Rejected: lat-91

~~~~
{
  "decision": "answer",
  "location": {
    "lat": 91,
    "lng": 4.76,
    "accuracy_m": 8,
    "precise": true
  }
}
~~~~

Rejected: photo-and-location

~~~~
{
  "decision": "answer",
  "photo": {
    "media_id": "med_01JAB2C3D4E5F6G7H8J9K0MNPQ"
  },
  "location": {
    "lat": 52.31,
    "lng": 4.76,
    "accuracy_m": 1200,
    "precise": false
  }
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('actor.approval-answer@1', value);   // { valid, errors: [{ path, message }] }
~~~~
