Skip to main content
The readOnly and writeOnly keywords indicate whether a property should be included in requests or responses. These are essential for API documentation and data flow control.

Syntax

The value of both keywords must be a boolean.
{
  "readOnly": true
}
{
  "writeOnly": true
}

Purpose

These keywords are metadata annotations that:
  • Control the directionality of data flow in APIs
  • Indicate which properties are managed by the server (readOnly)
  • Indicate which properties are never returned by the server (writeOnly)
  • Help generate appropriate user interfaces
  • Can be used by API documentation tools
  • Have no effect on validation (they are purely informational)

Behavior

When multiple occurrences of these keywords are applicable to a single sub-instance, the resulting behavior should be as for a true value if any occurrence specifies a true value, and should be as for a false value otherwise. Omitting these keywords has the same behavior as values of false.

readOnly

If readOnly has a value of boolean true, it indicates that the corresponding value in the instance is managed exclusively by the owning authority, and attempts by an application to modify the value are expected to be ignored or rejected by that owning authority. An instance document that is marked as readOnly for the entire document may be ignored if sent to the owning authority, or may result in an error, at the authority’s discretion.

readOnly Examples

Database-Generated ID

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid",
      "readOnly": true,
      "description": "Unique identifier generated by the server"
    },
    "name": {
      "type": "string"
    }
  }
}
The id field is generated by the server and cannot be set by clients.

Timestamps

{
  "type": "object",
  "title": "Article",
  "properties": {
    "title": {
      "type": "string"
    },
    "content": {
      "type": "string"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true,
      "description": "Timestamp when the article was created"
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true,
      "description": "Timestamp when the article was last updated"
    }
  }
}
Timestamps are managed by the server and cannot be modified by clients.

Computed Fields

{
  "type": "object",
  "title": "User",
  "properties": {
    "firstName": {
      "type": "string"
    },
    "lastName": {
      "type": "string"
    },
    "fullName": {
      "type": "string",
      "readOnly": true,
      "description": "Computed from firstName and lastName"
    },
    "profileUrl": {
      "type": "string",
      "format": "uri",
      "readOnly": true,
      "description": "Generated profile URL based on user ID"
    }
  }
}
Computed fields are derived by the server and cannot be set directly.

Status Fields

{
  "type": "object",
  "title": "Order",
  "properties": {
    "items": {
      "type": "array",
      "items": {"type": "object"}
    },
    "status": {
      "type": "string",
      "enum": ["pending", "processing", "shipped", "delivered"],
      "readOnly": true,
      "description": "Order status managed by the fulfillment system"
    },
    "totalPrice": {
      "type": "number",
      "readOnly": true,
      "description": "Calculated total price including tax and shipping"
    }
  }
}
Status and calculated fields are controlled by the system.

writeOnly

If writeOnly has a value of boolean true, it indicates that the value is never present when the instance is retrieved from the owning authority. It can be present when sent to the owning authority to update or create the document (or the resource it represents), but it will not be included in any updated or newly created version of the instance. An instance document that is marked as writeOnly for the entire document may be returned as a blank document of some sort, or may produce an error upon retrieval, or have the retrieval request ignored, at the authority’s discretion.

writeOnly Examples

Password Field

{
  "type": "object",
  "title": "User Registration",
  "properties": {
    "username": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "password": {
      "type": "string",
      "writeOnly": true,
      "minLength": 8,
      "description": "User password (never returned in responses)"
    }
  },
  "required": ["username", "email", "password"]
}
The password is accepted during registration but never returned in API responses.

Sensitive Data

{
  "type": "object",
  "title": "Payment Method",
  "properties": {
    "cardType": {
      "type": "string"
    },
    "last4Digits": {
      "type": "string",
      "readOnly": true,
      "description": "Last 4 digits of the card number"
    },
    "cardNumber": {
      "type": "string",
      "writeOnly": true,
      "pattern": "^[0-9]{13,19}$",
      "description": "Full card number (accepted but never returned)"
    },
    "cvv": {
      "type": "string",
      "writeOnly": true,
      "pattern": "^[0-9]{3,4}$",
      "description": "Card security code (never stored or returned)"
    }
  }
}
Sensitive payment information is write-only for security.

API Keys

{
  "type": "object",
  "title": "API Key",
  "properties": {
    "name": {
      "type": "string",
      "description": "Friendly name for the API key"
    },
    "apiKey": {
      "type": "string",
      "readOnly": true,
      "description": "The API key is only shown once at creation time"
    },
    "plainTextKey": {
      "type": "string",
      "writeOnly": true,
      "description": "Full API key (only returned once upon creation, then hashed)"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  }
}
API keys are only revealed once and then stored in hashed form.

Combined Usage

User Account Schema

{
  "type": "object",
  "title": "User Account",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "description": "System-generated user ID"
    },
    "username": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "password": {
      "type": "string",
      "writeOnly": true,
      "minLength": 8,
      "description": "User password (write-only)"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "lastLoginAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true,
      "description": "Timestamp of last successful login"
    }
  }
}
Combining both keywords for complete API resource modeling.

Password Change Request

{
  "type": "object",
  "title": "Change Password Request",
  "properties": {
    "currentPassword": {
      "type": "string",
      "writeOnly": true,
      "description": "User's current password for verification"
    },
    "newPassword": {
      "type": "string",
      "writeOnly": true,
      "minLength": 8,
      "description": "New password to set"
    },
    "passwordChangedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true,
      "description": "Timestamp when password was changed"
    }
  },
  "required": ["currentPassword", "newPassword"]
}
Password change operations use write-only inputs and read-only confirmation.

User Interface Applications

These keywords can be used to assist in user interface instance generation. In particular, an application may choose to use a widget that hides input values as they are typed for write-only fields.

Form Generation Example

{
  "type": "object",
  "title": "User Registration Form",
  "properties": {
    "username": {
      "type": "string",
      "title": "Username",
      "minLength": 3
    },
    "password": {
      "type": "string",
      "title": "Password",
      "writeOnly": true,
      "minLength": 8,
      "description": "Choose a strong password"
    },
    "userId": {
      "type": "string",
      "readOnly": true,
      "description": "Assigned after registration"
    }
  }
}
Form generators can:
  • Hide the userId field on creation forms (readOnly)
  • Use password input widgets for password (writeOnly)
  • Omit write-only fields from display forms

Best Practices

Mark Server-Managed Fields as readOnly

{
  "type": "object",
  "properties": {
    "id": {"type": "string", "readOnly": true},
    "createdAt": {"type": "string", "format": "date-time", "readOnly": true},
    "updatedAt": {"type": "string", "format": "date-time", "readOnly": true}
  }
}

Mark Secrets as writeOnly

{
  "type": "object",
  "properties": {
    "password": {"type": "string", "writeOnly": true},
    "apiSecret": {"type": "string", "writeOnly": true},
    "privateKey": {"type": "string", "writeOnly": true}
  }
}

Never Use Both on the Same Field

A field cannot be both readOnly and writeOnly:
// ❌ Invalid: conflicting directionality
{
  "type": "string",
  "readOnly": true,
  "writeOnly": true
}

Document the Reason

{
  "type": "object",
  "properties": {
    "emailVerificationToken": {
      "type": "string",
      "writeOnly": true,
      "description": "Token used to verify email address. Never returned for security reasons."
    }
  }
}

Build docs developers (and LLMs) love