idnits 2.17.1 draft-ietf-jmap-core-12.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- No issues found here. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (December 3, 2018) is 1961 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) -- Looks like a reference, but probably isn't: '1' on line 3326 ** Obsolete normative reference: RFC 5785 (Obsoleted by RFC 8615) ** Obsolete normative reference: RFC 7230 (Obsoleted by RFC 9110, RFC 9112) ** Obsolete normative reference: RFC 7235 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 7807 (Obsoleted by RFC 9457) Summary: 4 errors (**), 0 flaws (~~), 1 warning (==), 3 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 JMAP N. Jenkins 3 Internet-Draft FastMail 4 Intended status: Standards Track C. Newman 5 Expires: June 6, 2019 Oracle 6 December 3, 2018 8 JSON Meta Application Protocol 9 draft-ietf-jmap-core-12 11 Abstract 13 This document specifies a protocol for clients to efficiently query, 14 fetch and modify JSON-based data objects, with support for push 15 notification of changes and fast resynchronisation, and out-of-band 16 binary data upload/download. 18 Status of This Memo 20 This Internet-Draft is submitted in full conformance with the 21 provisions of BCP 78 and BCP 79. 23 Internet-Drafts are working documents of the Internet Engineering 24 Task Force (IETF). Note that other groups may also distribute 25 working documents as Internet-Drafts. The list of current Internet- 26 Drafts is at https://datatracker.ietf.org/drafts/current/. 28 Internet-Drafts are draft documents valid for a maximum of six months 29 and may be updated, replaced, or obsoleted by other documents at any 30 time. It is inappropriate to use Internet-Drafts as reference 31 material or to cite them other than as "work in progress." 33 This Internet-Draft will expire on June 6, 2019. 35 Copyright Notice 37 Copyright (c) 2018 IETF Trust and the persons identified as the 38 document authors. All rights reserved. 40 This document is subject to BCP 78 and the IETF Trust's Legal 41 Provisions Relating to IETF Documents 42 (https://trustee.ietf.org/license-info) in effect on the date of 43 publication of this document. Please review these documents 44 carefully, as they describe your rights and restrictions with respect 45 to this document. Code Components extracted from this document must 46 include Simplified BSD License text as described in Section 4.e of 47 the Trust Legal Provisions and are provided without warranty as 48 described in the Simplified BSD License. 50 Table of Contents 52 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 53 1.1. Notational conventions . . . . . . . . . . . . . . . . . 4 54 1.2. The Id data type . . . . . . . . . . . . . . . . . . . . 5 55 1.3. The Int and PositiveInt data types . . . . . . . . . . . 6 56 1.4. The Date and UTCDate data types . . . . . . . . . . . . . 6 57 1.5. JSON as the data encoding format . . . . . . . . . . . . 6 58 1.6. Terminology . . . . . . . . . . . . . . . . . . . . . . . 6 59 1.6.1. User . . . . . . . . . . . . . . . . . . . . . . . . 6 60 1.6.2. Accounts . . . . . . . . . . . . . . . . . . . . . . 7 61 1.6.3. Data types and records . . . . . . . . . . . . . . . 7 62 1.7. The JMAP API model . . . . . . . . . . . . . . . . . . . 7 63 1.8. Vendor-specific extensions . . . . . . . . . . . . . . . 8 64 2. The JMAP Session resource . . . . . . . . . . . . . . . . . . 9 65 2.1. Example . . . . . . . . . . . . . . . . . . . . . . . . . 12 66 2.2. Service autodiscovery . . . . . . . . . . . . . . . . . . 13 67 3. Structured data exchange . . . . . . . . . . . . . . . . . . 14 68 3.1. Making an API request . . . . . . . . . . . . . . . . . . 14 69 3.2. The Request object . . . . . . . . . . . . . . . . . . . 14 70 3.2.1. Example request . . . . . . . . . . . . . . . . . . . 15 71 3.3. The Response object . . . . . . . . . . . . . . . . . . . 15 72 3.3.1. Example response: . . . . . . . . . . . . . . . . . . 16 73 3.4. Omitting arguments . . . . . . . . . . . . . . . . . . . 16 74 3.5. Errors . . . . . . . . . . . . . . . . . . . . . . . . . 17 75 3.5.1. Request-level errors . . . . . . . . . . . . . . . . 17 76 3.5.2. Method-level errors . . . . . . . . . . . . . . . . . 18 77 3.6. References to previous method results . . . . . . . . . . 19 78 3.7. Security . . . . . . . . . . . . . . . . . . . . . . . . 24 79 3.8. Concurrency . . . . . . . . . . . . . . . . . . . . . . . 24 80 4. The Core/echo method . . . . . . . . . . . . . . . . . . . . 24 81 4.1. Example . . . . . . . . . . . . . . . . . . . . . . . . . 24 82 5. Standard methods and naming convention . . . . . . . . . . . 25 83 5.1. /get . . . . . . . . . . . . . . . . . . . . . . . . . . 25 84 5.2. /changes . . . . . . . . . . . . . . . . . . . . . . . . 26 85 5.3. /set . . . . . . . . . . . . . . . . . . . . . . . . . . 29 86 5.4. /copy . . . . . . . . . . . . . . . . . . . . . . . . . . 34 87 5.5. /query . . . . . . . . . . . . . . . . . . . . . . . . . 36 88 5.6. /queryChanges . . . . . . . . . . . . . . . . . . . . . . 40 89 5.7. Examples . . . . . . . . . . . . . . . . . . . . . . . . 43 90 5.8. Proxy considerations . . . . . . . . . . . . . . . . . . 49 91 6. Binary data . . . . . . . . . . . . . . . . . . . . . . . . . 50 92 6.1. Uploading binary data . . . . . . . . . . . . . . . . . . 51 93 6.2. Downloading binary data . . . . . . . . . . . . . . . . . 52 94 6.3. Blob/copy . . . . . . . . . . . . . . . . . . . . . . . . 52 95 7. Push . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 96 7.1. The StateChange object . . . . . . . . . . . . . . . . . 53 97 7.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 54 99 7.2. PushSubscription . . . . . . . . . . . . . . . . . . . . 54 100 7.2.1. PushSubscription/get . . . . . . . . . . . . . . . . 56 101 7.2.2. PushSubscription/set . . . . . . . . . . . . . . . . 57 102 7.2.3. Example . . . . . . . . . . . . . . . . . . . . . . . 57 103 7.3. Event Source . . . . . . . . . . . . . . . . . . . . . . 59 104 8. Security considerations . . . . . . . . . . . . . . . . . . . 60 105 8.1. Transport confidentiality . . . . . . . . . . . . . . . . 60 106 8.2. Authentication scheme . . . . . . . . . . . . . . . . . . 60 107 8.3. Service autodiscovery . . . . . . . . . . . . . . . . . . 60 108 8.4. JSON parsing . . . . . . . . . . . . . . . . . . . . . . 61 109 8.5. Denial of service . . . . . . . . . . . . . . . . . . . . 61 110 8.6. Connection to unknown push server . . . . . . . . . . . . 61 111 8.7. Push encryption . . . . . . . . . . . . . . . . . . . . . 61 112 9. IANA considerations . . . . . . . . . . . . . . . . . . . . . 62 113 9.1. Assignment of jmap service name . . . . . . . . . . . . . 62 114 9.2. Registration of well-known URI suffix for JMAP . . . . . 62 115 9.3. Registration of the jmap URN sub-namespace . . . . . . . 62 116 9.4. Creation of "JMAP Capabilities" registry . . . . . . . . 63 117 9.4.1. Preliminary community review . . . . . . . . . . . . 63 118 9.4.2. Submit request to IANA . . . . . . . . . . . . . . . 64 119 9.4.3. Designated expert review . . . . . . . . . . . . . . 64 120 9.4.4. Change procedures . . . . . . . . . . . . . . . . . . 64 121 9.4.5. JMAP Capabilities registry template: . . . . . . . . 65 122 9.4.6. Initial registration for JMAP core . . . . . . . . . 65 123 9.4.7. Registration for JMAP error placeholder in JMAP 124 capabilities registry . . . . . . . . . . . . . . . . 65 125 9.5. Creation of "JMAP Error Codes" registry . . . . . . . . . 65 126 9.5.1. Designated expert review . . . . . . . . . . . . . . 66 127 9.5.2. JMAP Error Codes registry template: . . . . . . . . . 66 128 9.5.3. Initial JMAP Error Codes registry . . . . . . . . . . 67 129 10. References . . . . . . . . . . . . . . . . . . . . . . . . . 69 130 10.1. Normative References . . . . . . . . . . . . . . . . . . 69 131 10.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 71 132 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 71 134 1. Introduction 136 JMAP is a protocol for synchronising data, such as mail, calendars or 137 contacts, between a client and a server. It is optimised for mobile 138 and web environments, and aims to provide a consistent interface to 139 different data types. 141 This specification is for the generic mechanism of data 142 synchronisation. Further specifications define the data models for 143 different data types that may be synchronised via JMAP. 145 JMAP is designed to make efficient use of limited network resources. 146 Multiple API calls may be batched in a single request to the server, 147 reducing round trips and improving battery life on mobile devices. 148 Push connections remove the need for polling, and an efficient delta 149 update mechanism ensures a minimum of data is transferred. 151 JMAP is designed to be horizontally scalable to a very large number 152 of users. This is facilitated by separate end points for users after 153 login, the separation of binary and structured data, and a data model 154 for sharing that does not allow data dependencies between accounts. 156 1.1. Notational conventions 158 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 159 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 160 document are to be interpreted as described in [RFC2119]. 162 The underlying format used for this specification is JSON. 163 Consequently, the terms "object" and "array" as well as the four 164 primitive types (strings, numbers, booleans, and null) are to be 165 interpreted as described in Section 1 of [RFC8259]. Unless otherwise 166 noted, all the property names and values are case sensitive. 168 Some examples in this document contain "partial" JSON documents used 169 for illustrative purposes. In these examples, three periods "..." 170 are used to indicate a portion of the document that has been removed 171 for compactness. 173 For compatibility with publishing requirements, line breaks have been 174 inserted inside long JSON strings, with the following continuation 175 lines indented. To form the valid JSON example, any line breaks 176 inside a string must be replaced with a space, and any other white- 177 space after the line break removed. 179 Unless otherwise specified, examples of API exchanges only show the 180 _methodCalls_ array of the Request object or the _methodResponses_ 181 array of the Response object. For compactness, the rest of the 182 Request/Response object is omitted. 184 Type signatures are given for all JSON values in this document. The 185 following conventions are used: 187 o "*" - The type is undefined (the value could be any type, although 188 permitted values may be constrained by the context of this value). 190 o "String" - The JSON string type. 192 o "Number" - The JSON number type. 194 o "Boolean" - The JSON boolean type. 196 o "String[A]" - A JSON object where the keys are all "String"s, and 197 the values are of type "A". 199 o "A[]" - An array of values of type "A". 201 o "A|B" - The value is either of type "A" or of type "B". 203 Other types may also be given, with their representation defined 204 elsewhere in this document. 206 Object properties may also have a set of attributes defined along 207 with the type signature. These have the following meanings: 209 o *server-set*: Only the server can set the value for this property. 210 The client MUST NOT send this property when creating a new object 211 of this type. 213 o *immutable*: The value MUST NOT change after the object is 214 created. 216 o *default*: (This is followed by a JSON value). The value that 217 will be used for this property if it is omitted in an argument, or 218 when creating a new object of this type. 220 1.2. The Id data type 222 All record ids are assigned by the server, and are immutable. 224 Where "Id" is given as a datatype, it means a "String" of at least 1 225 and maximum 255 octets in size, and MUST only contain characters from 226 the "URL and Filename safe" Base 64 Alphabet, as defined in section 5 227 of [RFC4648]. This is the ASCII alphanumeric characters ("A-Za- 228 z0-9"), hyphen ("-"), and underscore ("_"). 230 These characters are safe to use in almost any context (e.g., 231 filesystems, URIs, IMAP atoms). For maximum safety, servers should 232 also follow defensive allocation strategies to avoid creating risks 233 where glob completion or data type detection may be present (e.g., on 234 filesystems or in spreadsheets). In particular, it is wise to avoid: 236 o Ids starting with a dash 238 o Ids starting with digits 240 o Ids that contain only digits 242 o Ids that differ only by ASCII case (for example, A vs. a) 243 o the specific sequence of three characters "NIL" (because this 244 sequence can be confused with the IMAP protocol expression of the 245 null value) 247 A good solution to these issues is to prefix every id with a single 248 alphabetical character. 250 1.3. The Int and PositiveInt data types 252 Where "Int" is given as a data type, it means an integer in the range 253 -2^53+1 <= value <= 2^53-1, the safe range for integers stored in a 254 floating-point double, represented as a JSON "Number". 256 Where "PositiveInt" is given as a data type, it means an "Int" where 257 the value MUST be in the range 0 <= value <= 2^53-1. 259 1.4. The Date and UTCDate data types 261 Where "Date" is given as a type, it means a string in [RFC3339] 262 _date-time_ format. To ensure a normalised form, the _time-secfrac_ 263 MUST always be omitted if zero, and any letters in the string (e.g. 264 "T" and "Z") MUST be upper-case. For example, 265 ""2014-10-30T14:12:00+08:00"". 267 Where "UTCDate" is given as a type, it means a "Date" where the 268 _time-offset_ component MUST be "Z" (i.e. it must be in UTC time). 269 For example, ""2014-10-30T06:12:00Z"". 271 1.5. JSON as the data encoding format 273 JSON is a text-based data interchange format as specified in 274 [RFC8259]. The I-JSON format defined in [RFC7493] is a strict subset 275 of this, adding restrictions to avoid potentially confusing scenarios 276 (for example, it mandates that an object MUST NOT have two members 277 with the same name). 279 All data sent from the client to the server or from the server to the 280 client (except binary file upload/download) MUST be valid I-JSON 281 according to the RFC, and is therefore case-sensitive and encoded in 282 UTF-8 ([RFC3629]). 284 1.6. Terminology 286 1.6.1. User 288 A user represents a set of permissions relating to what data can be 289 seen. 291 1.6.2. Accounts 293 An account is a collection of data. A single account may contain an 294 arbitrary set of data types, for example a collection of mail, 295 contacts and calendars. 297 All data belong to a single account. Most JMAP methods take a 298 mandatory _accountId_ argument that specifies on which account the 299 operations are to take place. 301 An account is not the same as a user, although it is common for a 302 primary account to directly belong to the user. For example, you may 303 have an account that contains data for a group or business, to which 304 multiple users have access. 306 A single set of credentials may provide access to multiple accounts, 307 for example if another user is sharing their mail with the logged in 308 user, or if there is a group account. 310 In the event of a severe internal error, a server may have to 311 reallocate ids or do something else that violates standard JMAP data 312 constraints for an account. In this situation, the data on the 313 server is no longer compatible with cached data the client may have 314 from before. The server MUST treat this as though the account has 315 been deleted and then recreated with a new account id. Clients will 316 then be forced to throw away any data with the old account id and 317 refetch all data from scratch. 319 1.6.3. Data types and records 321 JMAP provides a uniform interface for creating, retrieving, updating 322 and deleting various types of objects. A *data type* is a collection 323 of named, typed properties, just like the schema for a database 324 table. Each instance of a data type is called a *record*. 326 The id of a record is immutable, and normally assigned by the server. 327 The id MUST be unique among all records of the *same type* within the 328 *same account*. Ids may clash across accounts, or for two records of 329 different types within the same account. 331 1.7. The JMAP API model 333 JMAP uses HTTP [RFC7230] to expose API, Push, Upload and Download 334 resources. Implementations MUST support HTTP/1.1, and MAY support 335 later versions. All HTTP requests MUST use [RFC8446] TLS (HTTPS) 336 transport. Support for common HTTP mechanisms such as redirection 337 and caching are assumed. 339 All HTTP requests MUST be authenticated. Servers MUST conform with 340 the [RFC7235] HTTP Authentication framework to reject requests that 341 fail authentication and inform the client of available authentication 342 schemes. 344 Clients MUST understand and be able to handle standard HTTP status 345 codes appropriately. 347 An authenticated client can fetch the JMAP Session object with 348 details about the data and capabilities the server can provide as 349 shown in section 2. The client may then exchange data with the 350 server in the following ways: 352 1. The client may make an API request to the server to get or set 353 structured data. This request consists of an ordered series of 354 method calls. These are processed by the server, which then 355 returns an ordered series of responses. This is described in 356 sections 3 to 5. 358 2. The client may download or upload binary files from/to the 359 server. This is detailed in section 6. 361 3. The client may connect to a push channel on the server, to be 362 notified when data has changed. This is explained in section 7. 364 1.8. Vendor-specific extensions 366 Individual services will have custom features they wish to expose 367 over JMAP. This may take the form of extra data types and/or methods 368 not in the spec, or extra arguments to JMAP methods, or extra 369 properties on existing data types (which may also appear in arguments 370 to methods that take property names). 372 The server can advertise custom extensions it supports by including 373 the identifiers in the capabilities object. Identifiers for vendor 374 extensions MUST be a URL belonging to a domain owned by the vendor, 375 to avoid conflict. The URL SHOULD resolve to documentation for the 376 changes the extension makes. 378 To ensure compatibility with clients that don't know about a specific 379 custom extension, and for compatibility with future versions of JMAP, 380 to use an extension the client MUST opt in by passing the appropriate 381 capability identifier in the _using_ array of the Request object, as 382 described in section 3.2. The server MUST only follow the 383 specifications that are opted-into and behave as though it does not 384 implement anything else when processing a request. 386 2. The JMAP Session resource 388 You need two things to connect to a JMAP server: 390 1. The URL for the JMAP Session resource. This may be requested 391 directly from the user, or discovered automatically based on a 392 username domain (see section 2.2 below). 394 2. Credentials to authenticate with. How to obtain credentials is 395 out of scope for this specification. 397 An authenticated GET request to the JMAP Session resource MUST return 398 the details about the data and capabilities the server can provide to 399 the client given those credentials. 401 The response to a successful request is a JSON-encoded *JMAP Session* 402 object. It has the following properties: 404 o *username*: "String" The username associated with the given 405 credentials. 407 o *accounts*: "Id[Account]" A map of *account id* to Account object 408 for each account (see section 1.5.2) the user has access to. An 409 *Account* object has the following properties: 411 * *name*: "String" A user-friendly string to show when presenting 412 content from this account, e.g. the email address representing 413 the owner of the account. 415 * *isPersonal*: "Boolean" This is "true" if the account belongs 416 to the authenticated user, rather than a group account or a 417 personal account of another user that has been shared with 418 them. 420 * *isReadOnly*: "Boolean" This is "true" if the entire account is 421 read-only. 423 * *hasDataFor*: "String[]" A list of specification URIs for the 424 object types supported in this account. The server advertises 425 the list of specifications it supports in general in the 426 capabilities object, as defined below. If the specification 427 includes new object type definitions, the server MUST include 428 it in the _hasDataFor_ array if, and only if, the user may use 429 those data types with this account. For example, you may have 430 access to your own account with mail, calendars and contacts 431 data, and also a shared account that only has contacts data (a 432 business address book for example). In this case the 433 _hasDataFor_ property on the first account would include 434 something like "urn:ietf:params:jmap:mail", 435 "urn:ietf:params:jmap:calendars", 436 "urn:ietf:params:jmap:contacts", while the second account would 437 just have the last of these. Attempts to use the methods 438 defined in a specification with one of the accounts that does 439 not contain those data types are rejected with an 440 _accountNotSupportedByMethod_ error (see section 3.5.2: method- 441 level errors). 443 o *primaryAccounts*: "String[Id]" A map of specification URIs (as 444 found in _hasDataFor_) to the account id to be considered the 445 user's main or default account for data pertaining to that 446 capability. If no account being returned belongs to the user, or 447 in any other way there is no appropriate way to determine a 448 default account, there MAY be no entry for a particular URI, even 449 though that specification is supported by the server (and in the 450 capabilities object). "urn:ietf:params:jmap:core" SHOULD NOT be 451 present. 453 o *capabilities*: "String[Object]" An object specifying the 454 capabilities of this server. Each key is a URI for a 455 specification supported by the server. The value for each of 456 these keys is an object with further information about the 457 server's capabilities in relation to that specification. The 458 client MUST ignore any properties it does not understand. The 459 capabilities object MUST include a property called 460 "urn:ietf:params:jmap:core". The value of this property is an 461 object which MUST contain the following information on server 462 capabilities (suggested minimum values for limits are supplied 463 that allow clients to make efficient use of the network): 465 * *maxSizeUpload*: "PositiveInt" The maximum file size, in 466 octets, that the server will accept for a single file upload 467 (for any purpose). Suggested minimum: 50,000,000. 469 * *maxConcurrentUpload*: "PositiveInt" The maximum number of 470 concurrent requests the server will accept to the upload 471 endpoint. Suggested minimum: 4. 473 * *maxSizeRequest*: "PositiveInt" The maximum size, in octets, 474 that the server will accept for a single request to the API 475 endpoint. Suggested minimum: 10,000,000. 477 * *maxConcurrentRequests*: "PositiveInt" The maximum number of 478 concurrent requests the server will accept to the API endpoint. 479 Suggested minimum: 4. 481 * *maxCallsInRequest*: "PositiveInt" The maximum number of method 482 calls the server will accept in a single request to the API 483 endpoint. Suggested minimum: 16. 485 * *maxObjectsInGet*: "PositiveInt" The maximum number of objects 486 that the client may request in a single "/get" type method 487 call. Suggested minimum: 500 489 * *maxObjectsInSet*: "PositiveInt" The maximum number of objects 490 the client may send to create, update or destroy in a single 491 "/set" type method call. This is the combined total, e.g. if 492 the maximum is 10 you could not create 7 objects and destroy 6, 493 as this would be 13 actions, which exceeds the limit. 494 Suggested minimum: 500. 496 * *collationAlgorithms*: "String[]" A list of identifiers for 497 algorithms registered in the collation registry defined in 498 [RFC4790] that the server supports for sorting when querying 499 records. 501 Future specifications will define their own properties on the 502 capabilities object. Servers MAY advertise vendor-specific JMAP 503 extensions, as described in section 1.7. To avoid conflict, the 504 identifiers for these MUST be a URL with a domain owned by the 505 vendor. Clients MUST opt in to any specifications it wishes to 506 use (see section 3.1). 508 o *apiUrl*: "String" The URL to use for JMAP API requests. 510 o *downloadUrl*: "String" The URL endpoint to use when downloading 511 files, in [RFC6570] URI Template (level 1) format. The URL MUST 512 contain variables called "accountId", "blobId", "type" and "name". 513 The use of these variables is described in section 6.2. Due to 514 potential encoding issues with slashes in content types, it is 515 recommended to put the "type" variable in the query section of the 516 URL. 518 o *uploadUrl*: "String" The URL endpoint to use when uploading 519 files, in [RFC6570] URI Template (level 1) format. The URL MUST 520 contain a variable called "accountId". The use of this variable 521 is described in section 6.1. 523 o *eventSourceUrl*: "String" The URL to connect to for push events, 524 as described in section 7.3. 526 o *state*: "String" A string representing the state of this object 527 on the server. If the value of any other property on the session 528 object changes, this string will change. The current value is 529 also returned on the API Response object (see section 3.3), 530 allowing clients to quickly determine if the session information 531 has changed (e.g. an account has been added or removed) and so 532 they need to refetch the object. 534 To ensure future compatibility, other properties MAY be included on 535 the JMAP Session object. Clients MUST ignore any properties they are 536 not expecting. 538 Implementors must take care to avoid inappropriate caching of the 539 session object at the HTTP layer. Since the client should only 540 refetch when it detects there is a change (via the sessionState 541 property of an API response), it is recommended to disable HTTP 542 caching altogether, for example by setting "Cache-Control: no-cache, 543 no-store, must-revalidate" on the response. 545 2.1. Example 547 In the following example JMAP Session object, the user has access to 548 their own mail and contacts via JMAP, as well as read-only access to 549 shared mail from another user. The server is advertising a custom 550 "https://example.com/apis/foobar" capability. 552 { 553 "username": "john@example.com", 554 "accounts": { 555 "13824": { 556 "name": "john@example.com", 557 "isPersonal": true, 558 "isReadOnly": false, 559 "hasDataFor": [ 560 "urn:ietf:params:jmap:mail", 561 "urn:ietf:params:jmap:contacts" 562 ] 563 }, 564 "97813": { 565 "name": "jane@example.com", 566 "isPersonal": false, 567 "isReadOnly": true, 568 "hasDataFor": [ "urn:ietf:params:jmap:mail" ] 569 } 570 }, 571 "primaryAccounts": { 572 "urn:ietf:params:jmap:mail": "13824", 573 "urn:ietf:params:jmap:contacts": "13824" 574 }, 575 "capabilities": { 576 "urn:ietf:params:jmap:core": { 577 "maxSizeUpload": 50000000, 578 "maxConcurrentUpload": 8, 579 "maxSizeRequest": 10000000, 580 "maxConcurrentRequest": 8, 581 "maxCallsInRequest": 32, 582 "maxObjectsInGet": 256, 583 "maxObjectsInSet": 128, 584 "collationAlgorithms": [ 585 "i;ascii-numeric", 586 "i;ascii-casemap", 587 "i;unicode-casemap" 588 ] 589 }, 590 "https://example.com/apis/foobar": { 591 "maxFoosFinangled": 42 592 }, 593 ... 594 }, 595 "apiUrl": "https://jmap.example.com/api/", 596 "downloadUrl": "https://jmap.example.com 597 /download/{accountId}/{blobId}/{name}?accept={type}", 598 "uploadUrl": "https://jmap.example.com/upload/{accountId}/", 599 "eventSourceUrl": "https://jmap.example.com/eventsource/", 600 "state": "75128aab4b1b" 601 } 603 2.2. Service autodiscovery 605 There are two standardised autodiscovery methods in use for internet 606 protocols: 608 o *DNS SRV* ([RFC2782], [RFC6186] and [RFC6764]) 610 o *.well-known/servicename* ([RFC5785]) 612 A JMAP-supporting host for the domain "example.com" SHOULD publish a 613 SRV record "_jmap._tcp.example.com" which gives a _hostname_ and 614 _port_ (usually port "443"). The JMAP Session resource is then 615 "https://${hostname}[:${port}]/.well-known/jmap" (following any 616 redirects). 618 If the client has a username in the form of an email address, it MAY 619 use the domain portion of this to attempt autodiscovery of the JMAP 620 server. 622 3. Structured data exchange 624 The client may make an API request to the server to get or set 625 structured data. This request consists of an ordered series of 626 method calls. These are processed by the server, which then returns 627 an ordered series of responses. 629 3.1. Making an API request 631 To make an API request, the client makes an authenticated POST 632 request to the API resource, which is defined by the _apiUrl_ 633 property in the JMAP Session object. 635 The request MUST be of type "application/json" and consist of a 636 single JSON *Request* object. If successful, the response MUST also 637 be of type "application/json" and consist of a single *Response* 638 object. 640 3.2. The Request object 642 A *Request* object has the following properties: 644 o *using*: "String[]" The set of capabilities the client wishes to 645 use. The client MAY include capability identifiers even if the 646 method calls it makes do not utilise those capabilities. The 647 server advertises the set of specifications it supports in the 648 JMAP Session object, as keys on the _capabilities_ property. 650 o *methodCalls*: "Invocation[]" An array of method calls to process 651 on the server. The method calls MUST be processed sequentially, 652 in order. An *Invocation* is a tuple, represented as a JSON array 653 containing three elements: 655 1. A "String" *name* of the method to call. 657 2. A "String[*]" object containing _named_ *arguments* for that 658 method. 660 3. A "String" *client id*: an arbitrary string from the client to 661 be echoed back with the responses emitted by that method call 662 (a method may return 1 or more responses, as it may make 663 implicit calls to other methods; all responses initiated by 664 this method call get the same client id in the response). 666 o *createdIds*: "Id[Id]" (optional) A map of (client-specified) 667 creation id to the id the server assigned when a record was 668 successfully created. As described later in this specification, 669 some records may have a property that contains the id of another 670 record. To allow more efficient network usage, you can set this 671 property to reference a record created earlier in the same API 672 request. Since the real id is unknown when the request is 673 created, the client can instead specify the creation id it 674 assigned, prefixed with a "#". As the server processes API 675 requests, any time it successfully creates a new record it adds to 676 this map the creation id, with the server-assigned real id as the 677 value. If it comes across a reference to a creation id in a 678 create/update, it looks it up in the map and replaces the 679 reference with the real id, if found. The client can pass an 680 initial value for this map as the _createdIds_ property of the 681 Request. This may be an empty object. If given in the request, 682 the response will also include a createdIds property, with any 683 additionally created ids added. This allows proxy servers to 684 easily split a JMAP request into multiple JMAP requests to send to 685 different servers. For example it could send the first two method 686 calls to server A, then the third to server B, before sending the 687 fourth to server A again. By passing the createdIds of the 688 previous response to the next request, it can ensure all of these 689 still resolve. See section 5.8 for further discussion of proxy 690 considerations. 692 Future specifications MAY add further properties to the Request 693 object to extend the semantics. To ensure forwards compatibility, a 694 server MUST ignore any other properties it does not understand on the 695 JMAP request object. 697 3.2.1. Example request 699 { 700 "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ], 701 "methodCalls": [ 702 [ "method1", { 703 "arg1": "arg1data", 704 "arg2": "arg2data" 705 }, "c1" ], 706 [ "method2", { 707 "arg1": "arg1data" 708 }, "c2" ], 709 [ "method3", {}, "c3" ] 710 ] 711 } 713 3.3. The Response object 715 A *Response* object has the following properties: 717 o *methodResponses*: "Invocation[]" An array of responses, in the 718 same format as the _methodCalls_ on the request object. The 719 output of the methods MUST be added to the _methodResponses_ array 720 in the same order as the methods are processed. 722 o *createdIds*: "Id[Id]" (optional; only returned if given in 723 request) A map of (client-specified) creation id to the id the 724 server assigned when a record was successfully created. This 725 includes all values passed in the request, as well as any 726 additional ones added for newly created records. 728 o *sessionState*: "String" The current value of the "state" string 729 on the JMAP Session object, as described in section 2. Clients 730 may use this to detect if this object has changed and needs to be 731 refetched. 733 Unless otherwise specified, if the method call completed successfully 734 its response name is the same as the method name in the request. 736 3.3.1. Example response: 738 { 739 "methodResponses": [ 740 [ "method1", { 741 "arg1": 3, 742 "arg2": "foo" 743 }, "c1" ], 744 [ "method2", { 745 "isBlah": true 746 }, "c2" ], 747 [ "anotherResponseFromMethod2", { 748 "data": 10, 749 "yetmoredata": "Hello" 750 }, "c2"], 751 [ "error", { 752 "type":"unknownMethod" 753 }, "c3" ] 754 ], 755 "sessionState": "75128aab4b1b" 756 } 758 3.4. Omitting arguments 760 An argument to a method may be specified to have a default value. If 761 omitted by the client, the server MUST treat the method call the same 762 as if the default value had been specified. Similarly, the server 763 MAY omit any argument in a response which has the default value. 765 Unless otherwise specified in a method description, "null" is the 766 default value for any argument in a request or response where this is 767 allowed by the type signature. Other arguments may only be omitted 768 if an explicit default value is defined in the method description. 770 3.5. Errors 772 There are three different levels of granularity at which an error may 773 be returned in JMAP. 775 When an API request is made, the request as a whole may be rejected 776 due to rate limiting, malformed JSON, request for an unknown 777 capability etc. In this case the entire request is rejected with an 778 appropriate HTTP error response code, and an additional JSON body 779 with more detail for the client. 781 Provided the request itself is syntactically valid, the methods 782 within it are executed sequentially by the server. Each method may 783 individually fail, for example if invalid arguments are given, or an 784 unknown method name is called. 786 Finally, methods that make changes to the server state often act upon 787 a number of different records within a single call. Each record 788 change may be separately rejected with a SetError, as described in 789 section 5.3. 791 3.5.1. Request-level errors 793 When an HTTP error response is returned to the client, the server 794 SHOULD return a JSON "problem details" object as the response body, 795 as per [RFC7807]. 797 The following problem types are defined: 799 o "urn:ietf:params:jmap:error:unknownCapability" The client included 800 a capability in the "using" property of the request that the 801 server does not support. 803 o "urn:ietf:params:jmap:error:notJSON" The content type of the 804 request was not "application/json" or the request did not parse as 805 I-JSON. 807 o "urn:ietf:params:jmap:error:notRequest" The request parsed as JSON 808 but did not match the structure of the Request object. 810 o "urn:ietf:params:jmap:error:limit" The request was not processed 811 as it would have exceeded one of the *request* limits defined on 812 the capability object, such as maxSizeRequest, maxCallsInRequest 813 or maxConcurrentRequests. A "limit" property MUST also be present 814 on the "problem details" object, containing the name of the limit 815 being applied. 817 3.5.1.1. Example 819 { 820 "type": "urn:ietf:params:jmap:error:unknownCapability", 821 "status": 400, 822 "detail": "The request object used capability 823 'https://example.com/apis/foobar', which is not supported 824 by this server." 825 } 827 3.5.2. Method-level errors 829 If a method encounters an error, the appropriate "error" response 830 MUST be inserted at the current point in the _methodResponses_ array 831 and, unless otherwise specified, further processing MUST NOT happen 832 within that method call. 834 Any further method calls in the request MUST then be processed as 835 normal. Errors at the method level MUST NOT generate an HTTP-level 836 error. 838 An "error" response looks like this: 840 [ "error", { 841 "type": "unknownMethod" 842 }, "client-id" ] 844 The response name is "error", and it MUST have a type property. 845 Other properties may be present with further information; these are 846 detailed in the error type descriptions where appropriate. 848 With the exception of "serverPartialFail", the externally-visible 849 state of the server MUST NOT have changed if an error is returned at 850 the method level. 852 The following error types are defined which may be returned for any 853 method call where appropriate: 855 "serverUnavailable": Some internal server resource was temporarily 856 unavailable. Attempting the same operation later (perhaps after a 857 backoff with a random factor) may succeed. 859 "serverFail": An unexpected or unknown error occurred during the 860 processing of the call. A _description_ property should provide more 861 details about the error. The method call made no changes to the 862 server's state. Attempting the same operation again is expected to 863 fail again. Contacting the service administrator is likely necessary 864 to resolve this problem if it is persistent. 866 "serverPartialFail": Some, but not all expected changes described by 867 the method occurred. The client MUST re-synchronise impacted data to 868 determine server state. Use of this error is strongly discouraged. 870 "unknownMethod": The server does not recognise this method name. 872 "invalidArguments": One of the arguments is of the wrong type or 873 otherwise invalid, or a required argument is missing. A 874 "description" property MAY be present to help debug with an 875 explanation of what the problem was. This is a non-localised string, 876 and is not intended to be shown directly to end users. 878 "invalidResultReference": The method used a back reference for one of 879 its arguments (see section 3.6), but this failed to resolve. 881 "forbidden": The method and arguments are valid, but executing the 882 method would violate an ACL or other permissions policy. 884 "accountNotFound": The _accountId_ does not correspond to a valid 885 account. 887 "accountNotSupportedByMethod": The _accountId_ given corresponds to a 888 valid account, but the account does not support this data type. 890 "accountReadOnly": This method call would modify state in an account 891 that is read-only (as returned on the corresponding Account object in 892 the JMAP Session resource). 894 Further possible errors for a particular method are specified in the 895 method descriptions. 897 Further general errors MAY be defined in future RFCs. Should a 898 client receive an error type it does not understand, it MUST treat it 899 the same as the "serverFail" type. 901 3.6. References to previous method results 903 To allow clients to make more efficient use of the network and avoid 904 round trips, an argument to one method can be taken from the result 905 of a previous method call in the same request. 907 To do this, the client prefixes the argument name with "#". The 908 value is a _ResultReference_ object as described below. When 909 processing a method call, the server MUST first check the arguments 910 object for any names beginning with "#". If found, the back 911 reference should be resolved and the value used as the "real" 912 argument. The method is then processed as normal. If any back 913 reference fails to resolve, the whole method MUST be rejected with an 914 "invalidResultReference" error. If an argument object contains the 915 same argument name in normal and referenced form (e.g. "foo" and 916 "#foo"), the method MUST return an "invalidArguments" error. 918 A *ResultReference* object has the following properties: 920 o *resultOf*: "String" The client id of the method call to get the 921 result from (the string given as the third item in the array for a 922 method call). 924 o *name*: "String" The expected name of the response. 926 o *path*: "String" A pointer into the arguments. This is an 927 [RFC6901] JSON Pointer, except it also allows the use of "*" to 928 map through an array (see description below). 930 To resolve: 932 1. Find the first response with a client id identical to the 933 _resultOf_ property of the _ResultReference_ in the 934 _methodResponses_ array from previously processed method calls in 935 the same request. If none, evaluation fails. 937 2. If the response name is not identical to the _name_ property of 938 the _ResultReference_, evaluation fails. 940 3. Apply the _path_ to the arguments object of the response (the 941 second item in the response array) following the [RFC6901] JSON 942 Pointer algorithm, except with the following addition in 943 Section 4 (Evaluation): 945 If the currently referenced value is a JSON array, the reference 946 token may be exactly the single character "*", making the new 947 referenced value the result of applying the rest of the JSON pointer 948 tokens to every item in the array and returning the results in the 949 same order in a new array. If the result of applying the rest of the 950 pointer tokens to a value was itself an array, its items should be 951 included individually in the output rather than including the array 952 itself (i.e. the result is flattened from an array of arrays to a 953 single array). 955 As a simple example, suppose we have the following API request 956 _methodCalls_: 958 [[ "Foo/changes", { 959 "accountId": "1", 960 "sinceState": "abcdef" 961 }, "t0" ], 962 [ "Foo/get", { 963 "accountId": "1", 964 "#ids": { 965 "resultOf": "t0", 966 "name": "Foo/changes", 967 "path": "/created" 968 } 969 }, "t1" ]] 971 After executing the first method call the _methodResponses_ array is: 973 [[ "Foo/changes", { 974 "accountId": "1", 975 "oldState": "abcdef", 976 "newState": "123456", 977 "hasMoreChanges": false, 978 "created": [ "f1", "f4" ], 979 "updated": [], 980 "destroyed": [] 981 }, "t0" ]] 983 To execute the Foo/get call, we look through the arguments and find 984 there is one with a "#" prefix. To resolve this, we apply the 985 algorithm above: 987 1. Find the first response with client id "t0". The Foo/changes 988 response fulfils this criterion. 990 2. Check the response name is the same as in the result reference. 991 It is, so this is fine. 993 3. Apply the _path_ as a JSON pointer to the arguments object. This 994 simply selects the "created" property, so the result of 995 evaluating is: "[ "f1", "f4" ]" 997 The JMAP server now continues to process the Foo/get call as though 998 the arguments were: 1000 { 1001 "accountId": "1", 1002 "ids": [ "f1", "f4" ] 1003 } 1005 Now a more complicated example using the JMAP Mail data model: fetch 1006 the "from"/"date"/"subject" for every email in the first 10 threads 1007 in the Inbox (sorted newest first): 1009 [[ "Email/query", { 1010 "accountId": "1", 1011 "filter": { "inMailbox": "id_of_inbox" }, 1012 "sort": [{ "property": "receivedAt", "isAscending": false }], 1013 "collapseThreads": true, 1014 "position": 0, 1015 "limit": 10, 1016 "calculateTotal": true 1017 }, "t0" ], 1018 [ "Email/get", { 1019 "accountId": "1", 1020 "#ids": { 1021 "resultOf": "t0", 1022 "name": "Email/query", 1023 "path": "/ids" 1024 }, 1025 "properties": [ "threadId" ] 1026 }, "t1" ], 1027 [ "Thread/get", { 1028 "accountId": "1", 1029 "#ids": { 1030 "resultOf": "t1", 1031 "name": "Email/get", 1032 "path": "/list/*/threadId" 1033 } 1034 }, "t2" ], 1035 [ "Email/get", { 1036 "accountId": "1", 1037 "#ids": { 1038 "resultOf": "t2", 1039 "name": "Thread/get", 1040 "path": "/list/*/emailIds" 1041 }, 1042 "properties": [ "from", "receivedAt", "subject" ] 1043 }, "t3" ]] 1045 After executing the first 3 method calls the _methodResponses_ array 1046 might be: 1048 [[ "Email/query", { 1049 "accountId": "1", 1050 "queryState": "abcdefg", 1051 "canCalculateChanges": true, 1052 "position": 0, 1053 "total": 101, 1054 "ids": [ "msg1023", "msg223", "msg110", "msg93", "msg91", 1055 "msg38", "msg36", "msg33", "msg11", "msg1" ] 1056 }, "t0" ], 1057 [ "Email/get", { 1058 "accountId": "1", 1059 "state": "123456", 1060 "list": [{ 1061 "id": "msg1023", 1062 "threadId": "trd194" 1063 }, { 1064 "id": "msg223", 1065 "threadId": "trd114" 1066 }, 1067 ... 1068 ], 1069 "notFound": [] 1070 }, "t1" ], 1071 [ "Thread/get", { 1072 "accountId": "1", 1073 "state": "123456", 1074 "list": [{ 1075 "id": "trd194", 1076 "emailIds": [ "msg1020", "msg1021", "msg1023" ] 1077 }, { 1078 "id": "trd114", 1079 "emailIds": [ "msg201", "msg223" ] 1080 }, 1081 ... 1082 ], 1083 "notFound": [] 1084 }, "t2" ]] 1086 So to execute the final Email/get call, we look through the arguments 1087 and find there is one with a "#" prefix. To resolve this, we apply 1088 the algorithm: 1090 1. Find the first response with client id "t2". The "Thread/get" 1091 response fulfils this criterion. 1093 2. "Thread/get" is the name specified in the result reference, so 1094 this is fine. 1096 3. Apply the _path_ as a JSON pointer to the arguments object. 1097 Token-by-token: 1099 1. "list": get the array of thread objects 1101 2. "*": for each of the items in the array: 1103 1. "emailIds": get the array of email ids 1105 2. Concatenate these into a single array of all the ids in 1106 the result. 1108 The JMAP server now continues to process the Email/get call as though 1109 the arguments were: 1111 { 1112 "accountId": "1", 1113 "ids": [ "msg1020", "msg1021", "msg1023", "msg201", "msg223", ... ], 1114 "properties": [ "from", "receivedAt", "subject" ] 1115 } 1117 3.7. Security 1119 As always, the server must be strict about data received from the 1120 client. Arguments need to be checked for validity; a malicious user 1121 could attempt to find an exploit through the API. In case of invalid 1122 arguments (unknown/insufficient/wrong type for data etc.) the method 1123 MUST return an "invalidArguments" error and terminate. 1125 3.8. Concurrency 1127 Method calls within a single request MUST be executed in order. 1128 However, method calls from different concurrent API requests may be 1129 interleaved. This means that the data on the server may change 1130 between two method calls within a single API request. 1132 4. The Core/echo method 1134 The _Core/echo_ method returns exactly the same arguments as it is 1135 given. It is useful for testing you have a valid authenticated 1136 connection to a JMAP API endpoint. 1138 4.1. Example 1140 Request: 1142 [[ "Core/echo", { 1143 "hello": true, 1144 "high": 5 1145 }, "b3ff" ]] 1147 Response: 1149 [[ "Core/echo", { 1150 "hello": true, 1151 "high": 5 1152 }, "b3ff" ]] 1154 5. Standard methods and naming convention 1156 JMAP provides a uniform interface for creating, retrieving, updating 1157 and deleting objects of a particular type. For a "Foo" data type, 1158 records of that type would be fetched via a "Foo/get" call and 1159 modified via a "Foo/set" call. Delta updates may be fetched via a 1160 "Foo/changes" call. These methods all follow a standard format as 1161 described below. 1163 Not all types may have all methods. Specifications defining types 1164 MUST specify which methods are available for the type. 1166 5.1. /get 1168 Objects of type *Foo* are fetched via a call to _Foo/get_. 1170 It takes the following arguments: 1172 o *accountId*: "Id" The id of the account to use. 1174 o *ids*: "Id[]|null" The ids of the Foo objects to return. If 1175 "null" then *all* records of the data type are returned, if this 1176 is supported for that data type. 1178 o *properties*: "String[]|null" If supplied, only the properties 1179 listed in the array are returned for each Foo object. If "null", 1180 all properties of the object are returned. The id property of the 1181 object is *always* returned, even if not explicitly requested. If 1182 an invalid property is requested, the call MUST be rejected with 1183 an "invalidArguments" error. 1185 The response has the following arguments: 1187 o *accountId*: "Id" The id of the account used for the call. 1189 o *state*: "String" A string representing the state on the server 1190 for *all* the data of this type in the account (not just the 1191 objects returned in this call). If the data changes, this string 1192 MUST change. If the Foo data is unchanged, servers SHOULD return 1193 the same state string on subsequent requests for this data type. 1194 When a client receives a response with a different state string to 1195 a previous call, it MUST either throw away all currently cached 1196 objects for the type, or call _Foo/changes_ to get the exact 1197 changes. 1199 o *list*: "Foo[]" An array of the Foo objects requested. This is 1200 the *empty array* if no objects were found, or if the _ids_ 1201 argument passed in was also the empty array. The results MAY be 1202 in a different order to the _ids_ in the request arguments. If an 1203 identical id is included more than once in the request, the server 1204 MUST only include it once in either the _list_ or _notFound_ 1205 argument of the response. 1207 o *notFound*: "Id[]" This array contains the ids passed to the 1208 method for records that do not exist. The array is empty if all 1209 requested ids were found, or if the _ids_ argument passed in was 1210 either "null" or the empty array. 1212 The following additional error may be returned instead of the _Foo/ 1213 get_ response: 1215 "requestTooLarge": The number of _ids_ requested by the client 1216 exceeds the maximum number the server is willing to process in a 1217 single method call. 1219 5.2. /changes 1221 When the state of the set of Foo records in an account changes on the 1222 server (whether due to creation, updates or deletion), the _state_ 1223 property of the _Foo/get_ response will change. The _Foo/changes_ 1224 method allows a client to efficiently update the state of its Foo 1225 cache to match the new state on the server. It takes the following 1226 arguments: 1228 o *accountId*: "Id" The id of the account to use. 1230 o *sinceState*: "String" The current state of the client. This is 1231 the string that was returned as the _state_ argument in the _Foo/ 1232 get_ response. The server will return the changes that have 1233 occurred since this state. 1235 o *maxChanges*: "PositiveInt|null" The maximum number of ids to 1236 return in the response. The server MAY choose to return fewer 1237 than this value, but MUST NOT return more. If not given by the 1238 client, the server may choose how many to return. If supplied by 1239 the client, the value MUST be a positive integer greater than 0. 1240 If a value outside of this range is given, the server MUST reject 1241 the call with an "invalidArguments" error. 1243 The response has the following arguments: 1245 o *accountId*: "Id" The id of the account used for the call. 1247 o *oldState*: "String" This is the _sinceState_ argument echoed 1248 back; the state from which the server is returning changes. 1250 o *newState*: "String" This is the state the client will be in after 1251 applying the set of changes to the old state. 1253 o *hasMoreChanges*: "Boolean" If "true", the client may call _Foo/ 1254 changes_ again with the _newState_ returned to get further 1255 updates. If "false", _newState_ is the current server state. 1257 o *created*: "Id[]" An array of ids for records which have been 1258 created since the old state. 1260 o *updated*: "Id[]" An array of ids for records which have been 1261 updated since the old state. 1263 o *destroyed*: "Id[]" An array of ids for records which have been 1264 destroyed since the old state. 1266 If a record has been created AND updated since the old state, the 1267 server SHOULD just return the id in the _created_ list, but MAY 1268 return it in the _updated_ list as well. 1270 If a record has been updated AND destroyed since the old state, the 1271 server SHOULD just return the id in the _destroyed_ list, but MAY 1272 return it in the _updated_ list as well. 1274 If a record has been created AND destroyed since the old state, the 1275 server SHOULD remove the id from the response entirely, but MAY 1276 include it in the _destroyed_ list, and if so MAY also include it in 1277 the _created_ list. 1279 If a _maxChanges_ is supplied, or set automatically by the server, 1280 the server MUST ensure the number of ids returned across _created_, 1281 _updated_ and _destroyed_ does not exceed this limit. If there are 1282 more changes than this between the client's state and the current 1283 server state, the server SHOULD generate an update to take the client 1284 to an intermediate state, from which the client can continue to call 1285 _Foo/changes_ until it is fully up to date. If it is unable to 1286 calculate an intermediate state, it MUST return a 1287 "cannotCalculateChanges" error response instead. 1289 When generating intermediate states, the server may choose how to 1290 divide up the changes. For many types it will provide a better user 1291 experience to return the more recent changes first, as this is more 1292 likely to be what the user is most interested in. The client can 1293 then continue to page in the older changes while the user is viewing 1294 the newer data. For example, suppose a server went through the 1295 following states: 1297 A -> B -> C -> D -> E 1299 And a client asks for changes from state "B". The server might first 1300 get the ids of records created, updated or destroyed between states D 1301 and E, returning them with: 1303 state: "B-D-E" 1304 hasMoreChanges: true 1306 The client will then ask for the change from state "B-D-E", and the 1307 server can return the changes between states C and D, returning: 1309 state: "B-C-E" 1310 hasMoreChanges: true 1312 Finally the client will request the changes from "B-C-E" and the 1313 server can return the changes between states B and C, returning: 1315 state: "E" 1316 hasMoreChanges: false 1318 Should the state on the server be modified in the middle of all this 1319 (to "F"), the server still does the same but now when the update to 1320 state "E" is returned, it would indicate that it still has more 1321 changes for the client to fetch. 1323 Where multiple changes to a record are split across different 1324 intermediate states, the server MUST NOT return a record as created 1325 in a later response than one which gives it as updated or destroyed, 1326 and MUST NOT return a record as destroyed before a response that 1327 gives it as created or updated. The server may have to coalesce 1328 multiple changes to a record to satisfy this requirement. 1330 The following additional errors may be returned instead of the _Foo/ 1331 changes_ response: 1333 "cannotCalculateChanges": The server cannot calculate the changes 1334 from the state string given by the client. Usually due to the 1335 client's state being too old, or the server being unable to produce 1336 an update to an intermediate state when there are too many updates. 1337 The client MUST invalidate its Foo cache. 1339 Maintaining state to allow calculation of _Foo/changes_ can be 1340 expensive for the server, but always returning 1341 _cannotCalculateChanges_ severely increases network traffic and 1342 resource usage for the client. To allow efficient sync, servers 1343 SHOULD be able to calculate changes from any state string that was 1344 given to a client within the last 30 days (but of course may support 1345 calculating updates from states older than this). 1347 5.3. /set 1349 Modifying the state of Foo objects on the server is done via the 1350 _Foo/set_ method. This encompasses creating, updating and destroying 1351 Foo records. This allows the server to sort out ordering and 1352 dependencies that may exist if doing multiple operations at once (for 1353 example to ensure there is always a minimum number of a certain 1354 record type). 1356 The _Foo/set_ method takes the following arguments: 1358 o *accountId*: "Id" The id of the account to use. 1360 o *ifInState*: "String|null" This is a state string as returned by 1361 the _Foo/get_ method. If supplied, the string must match the 1362 current state, otherwise the method will be aborted and a 1363 "stateMismatch" error returned. If "null", any changes will be 1364 applied to the current state. 1366 o *create*: "Id[Foo]|null" A map of _creation id_ (a temporary id 1367 set by the client) to Foo objects, or "null" if no objects are to 1368 be created. The Foo object type definition may define default 1369 values for properties. Any such property may be omitted by the 1370 client. The client MUST omit any properties that may only be set 1371 by the server (for example, the _id_ property on most object 1372 types). 1374 o *update*: "Id[PatchObject]|null" A map of id to a Patch object to 1375 apply to the current Foo object with that id, or "null" if no 1376 objects are to be updated. A _PatchObject_ is of type 1377 "String[*]", and represents an unordered set of patches. The keys 1378 are a path in [RFC6901] JSON pointer format, with an implicit 1379 leading "/" (i.e. prefix each key with "/" before applying the 1380 JSON pointer evaluation algorithm). All paths MUST also conform 1381 to the following restrictions; if there is any violation, the 1382 update MUST be rejected with an "invalidPatch" error: 1384 * The pointer MUST NOT reference inside an array (i.e. you MUST 1385 NOT insert/delete from an array; the array MUST be replaced in 1386 its entirety instead). 1388 * All parts prior to the last (i.e. the value after the final 1389 slash) MUST already exist on the object being patched. 1391 * There MUST NOT be two patches in the PatchObject where the 1392 pointer of one is the prefix of the pointer of the other, e.g. 1393 "alerts/1/offset" and "alerts". 1395 The value associated with each pointer determines how to apply 1396 that patch: 1398 * If "null", set to the default value if specified for this 1399 property, otherwise remove the property from the patched 1400 object. If the key is not present in the parent, this a no-op. 1402 * Anything else: The value to set for this property (this may be 1403 a replacement or addition to the object being patched). 1405 Any server-set properties MAY be included in the patch if their 1406 value is identical to the current server value (before applying 1407 the patches to the object). Otherwise, the update MUST be 1408 rejected with an _invalidProperties_ SetError. This patch 1409 definition is designed such that an entire Foo object is also a 1410 valid PatchObject. The client MAY choose to optimise network 1411 usage by just sending the diff, or MAY just send the whole object; 1412 the server processes it the same either way. 1414 o *destroy*: "Id[]|null" A list of ids for Foo objects to 1415 permanently delete, or "null" if no objects are to be destroyed. 1417 Each creation, modification or destruction of an object is considered 1418 an atomic unit. It is permissible for the server to commit changes 1419 to some objects but not others, however it MUST NOT only commit part 1420 of an update to a single record (e.g. update a _name_ property but 1421 not a _count_ property, if both are supplied in the update object). 1423 The final state MUST be valid after the Foo/set is finished, however 1424 the server may have to transition through invalid intermediate states 1425 (not exposed to the client) while processing the individual 1426 create/update/destroy requests. For example, suppose there is a 1427 "name" property that must be unique. A single method call could 1428 rename an object A => B, and simultaneously rename another object B 1429 => A. If the final state is valid, this is allowed. Otherwise, each 1430 creation, modification or destruction of an object should be 1431 processed sequentially and accepted/rejected based on the current 1432 server state. 1434 If a create, update or destroy is rejected, the appropriate error 1435 MUST be added to the notCreated/notUpdated/notDestroyed property of 1436 the response and the server MUST continue to the next create/update/ 1437 destroy. It does not terminate the method. 1439 If an id given cannot be found, the update or destroy MUST be 1440 rejected with a "notFound" set error. 1442 The server MAY skip an update (rejecting it with a "willDestroy" 1443 SetError) if that object is destroyed in the same /set request. 1445 Some records may hold references to other records (foreign keys). 1446 That reference may be set (via create or update) in the same request 1447 as the referenced record is created. To do this, the client refers 1448 to the new record using its creation id prefixed with a "#". The 1449 order of the method calls in the request by the client MUST be such 1450 that the record being referenced is created in the same or an earlier 1451 call. The server thus never has to look ahead. Instead, while 1452 processing a request the server MUST keep a simple map for the 1453 duration of the request of creation id to record id for each newly 1454 created record, so it can substitute in the correct value if 1455 necessary in later method calls. 1457 Creation ids are not scoped by type but are a single map for all 1458 types. A client SHOULD NOT reuse a creation id anywhere in the same 1459 API request. If a creation id is reused, the server MUST map the 1460 creation id to the most recently created item with that id. To allow 1461 easy proxying of API requests, an initial set of creation id to real 1462 id values may be passed with a request (see The Request object in 1463 section 3.2) and the final state of the map passed out with the 1464 response (see section 3.3). 1466 The response has the following arguments: 1468 o *accountId*: "Id" The id of the account used for the call. 1470 o *oldState*: "String|null" The state string that would have been 1471 returned by _Foo/get_ before making the requested changes, or 1472 "null" if the server doesn't know what the previous state string 1473 was. 1475 o *newState*: "String" The state string that will now be returned by 1476 _Foo/get_. 1478 o *created*: "Id[Foo]|null" A map of the creation id to an object 1479 containing any properties of the created Foo object that were not 1480 sent by the client. This includes all server-set properties (such 1481 as the _id_ in most object types) and any properties that were 1482 omitted by the client and so set to a default by the server. This 1483 argument is "null" if no Foo objects were successfully created. 1485 o *updated*: "Id[Foo|null]|null" The _keys_ in this map are the ids 1486 of all Foos that were successfully updated. The _value_ for each 1487 id is a Foo object containing any property that changed in a way 1488 _not_ explicitly requested by the _PatchObject_ sent to the 1489 server, or "null" if none. This lets the client know of any 1490 changes to server-set or computed properties. This argument is 1491 "null" if no Foo objects were successfully updated. 1493 o *destroyed*: "Id[]|null" A list of Foo ids for records that were 1494 successfully destroyed, or "null" if none. 1496 o *notCreated*: "Id[SetError]|null" A map of creation id to a 1497 SetError object for each record that failed to be created, or 1498 "null" if all successful. 1500 o *notUpdated*: "Id[SetError]|null" A map of Foo id to a SetError 1501 object for each record that failed to be updated, or "null" if all 1502 successful. 1504 o *notDestroyed*: "Id[SetError]|null" A map of Foo id to a SetError 1505 object for each record that failed to be destroyed, or "null" if 1506 all successful. 1508 A *SetError* object has the following properties: 1510 o *type*: "String" The type of error. 1512 o *description*: "String|null" A description of the error to help 1513 debug with an explanation of what the problem was. This is a non- 1514 localised string, and is not intended to be shown directly to end 1515 users. 1517 The following SetError types are defined and may be returned for set 1518 operations on any record type where appropriate: 1520 o "forbidden": (create; update; destroy) The create/update/destroy 1521 would violate an ACL or other permissions policy. 1523 o "overQuota": (create; update) The create would exceed a server- 1524 defined limit on the number or total size of objects of this type. 1526 o "tooLarge": (create; update) The create/update would result in an 1527 object that exceeds a server-defined limit for the maximum size of 1528 a single object of this type. 1530 o "rateLimit": (create) Too many objects of this type have been 1531 created recently, and a server-defined rate limit has been 1532 reached. It may work if tried again later. 1534 o "notFound": (update; destroy) The id given to update/destroy 1535 cannot be found. 1537 o "invalidPatch": (update) The PatchObject given to update the 1538 record was not a valid patch (see the patch description). 1540 o "willDestroy" (update) The client requested an object be both 1541 updated and destroyed in the same /set request, and the server has 1542 decided to therefore ignore the update. 1544 o "invalidProperties": (create; update) The record given is invalid 1545 in some way. For example: 1547 * It contains properties which are invalid according to the type 1548 specification of this record type. 1550 * It contains a property that may only be set by the server (e.g. 1551 "id") and is different to the current value. Note, to allow 1552 clients to pass whole objects back, it is not an error to 1553 include a server-set property in an update so long as the value 1554 is identical to the current value on the server. 1556 * There is a reference to another record (foreign key) and the 1557 given id does not correspond to a valid record. 1559 The SetError object SHOULD also have a property called 1560 _properties_ of type "String[]" that lists *all* the properties 1561 that were invalid. Individual methods MAY specify more specific 1562 errors for certain conditions that would otherwise result in an 1563 invalidProperties error. If the condition of one of these is met, 1564 it MUST be returned instead of the invalidProperties error. 1566 o "singleton": (create; destroy) This is a singleton type, so you 1567 cannot create another one or destroy the existing one. 1569 Other possible SetError types MAY be given in specific method 1570 descriptions. Other properties MAY also be present on the _SetError_ 1571 object, as described in the relevant methods. 1573 The following additional errors may be returned instead of the _Foo/ 1574 set_ response: 1576 "requestTooLarge": The total number of objects to create, update or 1577 destroy exceeds the maximum number the server is willing to process 1578 in a single method call. 1580 "stateMismatch": An "ifInState" argument was supplied and it does not 1581 match the current state. 1583 5.4. /copy 1585 The only way to move Foo records *between* two different accounts is 1586 to copy them using the _Foo/copy_ method, then once the copy has 1587 succeeded, delete the original. The _onSuccessDestroyOriginal_ 1588 argument allows you to try to do this in one method call, however 1589 note that the two different actions are not atomic, and so it is 1590 possible for the copy to succeed but the original not to be destroyed 1591 for some reason. 1593 The copy is conceptually in three phases: 1595 1. Reading the current values from the "from" account. 1597 2. Writing the new copies to the other account. 1599 3. Destroying the originals in the "from" account, if requested. 1601 Data may change in between phases due to concurrent requests. 1603 The _Foo/copy_ method takes the following arguments: 1605 o *fromAccountId*: "Id" The id of the account to copy records from. 1607 o *ifFromInState*: "String|null" This is a state string as returned 1608 by the _Foo/get_ method. If supplied, the string must match the 1609 current state of the account referenced by the fromAccountId when 1610 reading the data to be copied, otherwise the method will be 1611 aborted and a "stateMismatch" error returned. If "null", the data 1612 will be read from the current state. 1614 o *accountId*: "Id" The id of the account to copy records to. This 1615 MUST be different to the "fromAccountId". 1617 o *ifInState*: "String|null" This is a state string as returned by 1618 the _Foo/get_ method. If supplied, the string must match the 1619 current state of the account referenced by the accountId, 1620 otherwise the method will be aborted and a "stateMismatch" error 1621 returned. If "null", any changes will be applied to the current 1622 state. 1624 o *create*: "Id[Foo]" A map of _creation id_ to a Foo object. The 1625 object MUST contain an id property: the id (in the fromAccount) of 1626 the record to be copied. Any other properties included are used 1627 instead of the current value for that property on the original 1628 when creating the copy. 1630 o *onSuccessDestroyOriginal*: "Boolean" (default: false) If "true", 1631 an attempt will be made to destroy the original records that were 1632 successfully copied: after emitting the _Foo/copy_ response, but 1633 before processing the next method, the server MUST make a single 1634 call to _Foo/set_ to destroy the original of each successfully 1635 copied record; the output of this is added to the responses as 1636 normal to be returned to the client. 1638 o *destroyFromIfInState*: "String|null" This argument is passed on 1639 as the "ifInState" argument to the implicit _Foo/set_ call, if 1640 made at the end of this request. 1642 Each record copy is considered an atomic unit which may succeed or 1643 fail individually. 1645 The response has the following arguments: 1647 o *fromAccountId*: "Id" The id of the account records were copied 1648 from. 1650 o *accountId*: "Id" The id of the account records were copied to. 1652 o *oldState*: "String|null" The state string that would have been 1653 returned by _Foo/get_ on the account records were copied to before 1654 making the requested changes, or "null" if the server doesn't know 1655 what the previous state string was. 1657 o *newState*: "String" The state string that will now be returned by 1658 _Foo/get_ on the account records were copied to. 1660 o *created*: "Id[Foo]|null" A map of the creation id to an object 1661 containing any properties of the copied Foo object that are set by 1662 the server (such as the _id_ in most object types). This argument 1663 is "null" if no Foo objects were successfully copied. 1665 o *notCreated*: "Id[SetError]|null" A map of creation id to a 1666 SetError object for each record that failed to be copied, "null" 1667 if none. 1669 The *SetError* may be any of the standard set errors that may be 1670 returned for a _create_ or _update_. In addition, the following 1671 SetError is defined: 1673 "alreadyExists": The server forbids duplicates and the record already 1674 exists in the target account. An _existingId_ property of type "Id" 1675 MUST be included on the error object with the id of the existing 1676 record. 1678 The following additional errors may be returned instead of the _Foo/ 1679 copy_ response: 1681 "fromAccountNotFound": The _fromAccountId_ does not correspond to a 1682 valid account. 1684 "fromAccountNotSupportedByMethod": The _fromAccountId_ given 1685 corresponds to a valid account, but the account does not support this 1686 data type. 1688 "stateMismatch": An "ifInState" argument was supplied and it does not 1689 match the current state, or an "ifFromInState" argument was supplied 1690 and it does not match the current state in the from account. 1692 5.5. /query 1694 For data sets where the total amount of data is expected to be very 1695 small, clients can just fetch the complete set of data and then do 1696 any sorting/filtering locally. However, for large data sets (e.g. 1697 multi-gigabyte mailboxes), the client needs to be able to 1698 search/sort/window the data type on the server. 1700 A query on the set of Foos in an account is made by calling _Foo/ 1701 query_. This takes a number of arguments to determine which records 1702 to include, how they should be sorted, and which part of the result 1703 should be returned (the full list may be _very_ long). The result is 1704 returned as a list of Foo ids. 1706 A call to _Foo/query_ takes the following arguments: 1708 o *accountId*: "Id" The id of the account to use. 1710 o *filter*: "FilterOperator|FilterCondition|null" Determines the set 1711 of Foos returned in the results. If "null", all objects in the 1712 account of this type are included in the results. A 1713 *FilterOperator* object has the following properties: 1715 * *operator*: "String" This MUST be one of the following strings: 1716 "AND" / "OR" / "NOT": 1718 + *AND*: all of the conditions must match for the filter to 1719 match. 1721 + *OR*: at least one of the conditions must match for the 1722 filter to match. 1724 + *NOT*: none of the conditions must match for the filter to 1725 match. 1727 * *conditions*: "(FilterOperator|FilterCondition)[]" The 1728 conditions to evaluate against each record. 1730 A *FilterCondition* is an "object" whose allowed properties and 1731 semantics depend on the data type and is defined in the _/query_ 1732 method specification for that type. It MUST NOT have an 1733 _operator_ property. 1735 o *sort*: "Comparator[]|null" Lists the names of properties to 1736 compare between two Foo records, and how to compare them, to 1737 determine which comes first in the sort. If two Foo records have 1738 an identical value for the first comparator, the next comparator 1739 will be considered and so on. If all comparators are the same 1740 (this includes the case where an empty array or "null" is given as 1741 the _sort_ argument), the sort order is server-dependent, but MUST 1742 be stable between calls to Foo/query. A *Comparator* has the 1743 following properties: 1745 * *property*: "String" The name of the property on the Foo 1746 objects to compare. 1748 * *isAscending*: "Boolean" (optional; default: true) If "true", 1749 sort in ascending order. If "false", reverse the comparator's 1750 results to sort in descending order. 1752 * *collation*: "String" (optional; default is server-dependent) 1753 The identifier, as registered in the collation registry defined 1754 in [RFC4790], for the algorithm to use when comparing the order 1755 of strings. The algorithms the server supports are advertised 1756 in the capabilities object returned with the JMAP Session 1757 object. If omitted, the default algorithm is server-dependent, 1758 but: 1760 1. It MUST be unicode-aware. 1762 2. It SHOULD have reasonable default behavior for many 1763 languages when the user's language is unknown. 1765 3. It MAY be selected based on out-of-band information about 1766 the user's language/locale. 1768 4. It SHOULD be case-insensitive where such a concept makes 1769 sense for a language/locale. 1771 The "i;unicode-casemap" collation ([RFC5051]) and the Unicode 1772 Collation Algorithm () 1773 are two examples that fulfil these criterion. When the 1774 property being compared is not a string, the _collation_ 1775 property is ignored and the following comparison rules apply 1776 based on the type. In ascending order: 1778 + "Boolean": "false" comes before "true". 1780 + "Number": A lower number comes before a higher number. 1782 + "Date"/"UTCDate": The earlier date comes first. 1784 The Comparator object may also have additional properties as 1785 required for specific sort operations defined in a type's /query 1786 method. 1788 o *position*: "Int" (default: 0) The 0-based index of the first id 1789 in the full list of results to return. If a negative value is 1790 given, it is an offset from the end of the list. Specifically, 1791 the negative value MUST be added to the total number of results 1792 given the filter, and if still negative clamped to "0". This is 1793 now the 0-based index of the first id to return. If the index is 1794 greater than or equal to the total number of objects in the 1795 results list then the _ids_ array in the response will be empty, 1796 but this is not an error. 1798 o *anchor*: "Id|null" A Foo id. If supplied the _position_ argument 1799 is ignored. The index of this id in the results will be used in 1800 combination with the "anchorOffset" argument to determine the 1801 index of the first result to return (see below for more details). 1803 o *anchorOffset*: "Int" (default: 0) The index of the first result 1804 to return relative to the index of the anchor, if an anchor is 1805 given. This MAY be negative. For example, "-1" means the Foo 1806 immediately preceding the anchor is the first result in the list 1807 returned (see below for more details). 1809 o *limit*: "PositiveInt|null" The maximum number of results to 1810 return. If "null", no limit presumed. The server MAY choose to 1811 enforce a maximum "limit" argument. In this case, if a greater 1812 value is given (or if it is "null"), the limit is clamped to the 1813 maximum; the new limit is returned with the response so the client 1814 is aware. If a negative value is given, the call MUST be rejected 1815 with an "invalidArguments" error. 1817 o *calculateTotal*: "Boolean" (default: false) Does the client wish 1818 to know the total number of results in the query? This may be 1819 slow and expensive for servers to calculate, particularly with 1820 complex filters, so clients should take care to only request the 1821 total when needed. 1823 If an *anchor* argument is given, then after filtering and sorting 1824 the anchor is looked for in the results. If found, the *anchor 1825 offset* is then added to its index. If the resulting index is now 1826 negative, it is clamped to 0. This index is now used exactly as 1827 though it were supplied as the "position" argument. If the anchor is 1828 not found, the call is rejected with an "anchorNotFound" error. 1830 If an _anchor_ is specified, any position argument supplied by the 1831 client MUST be ignored. If no _anchor_ is supplied, any anchor 1832 offset argument MUST be ignored. 1834 A client can use _anchor_ instead of _position_ to find the index of 1835 an id within a large set of results. 1837 The response has the following arguments: 1839 o *accountId*: "Id" The id of the account used for the call. 1841 o *queryState*: "String" A string encoding the current state of the 1842 query on the server. This string MUST change if the results of 1843 the query (i.e. the matching ids and their sort order) have 1844 changed. The queryState string MAY change if something has 1845 changed on the server which means the results may have changed but 1846 the server doesn't know for sure. The queryState string only 1847 represents the ordered list of ids that match the particular query 1848 (including its sort/filter). There is no requirement for it to 1849 change if a property on an object matching the query changes but 1850 the query results are unaffected (indeed, it is more efficient if 1851 the queryState string does not change in this case). The 1852 queryState string only has meaning when compared to future 1853 responses to a query with the same type/sort/filter, or when used 1854 with /queryChanges to fetch changes. Should a client receive back 1855 a response with a different queryState string to a previous call 1856 it MUST either throw away the currently cached query and fetch it 1857 again (note, this does not require fetching the records again, 1858 just the list of ids) or call _Foo/queryChanges_ to get the 1859 difference. 1861 o *canCalculateChanges*: "Boolean" This is "true" if the server 1862 supports calling _Foo/queryChanges_ with these "filter"/"sort" 1863 parameters. Note, this does not guarantee that the _Foo/ 1864 queryChanges_ call will succeed, as it may only be possible for a 1865 limited time afterwards due to server internal implementation 1866 details. 1868 o *position*: "PositiveInt" The 0-based index of the first result in 1869 the "ids" array within the complete list of query results. 1871 o *ids*: "Id[]" The list of ids for each foo in the query results, 1872 starting at the index given by the _position_ argument of this 1873 response, and continuing until it hits the end of the results or 1874 reaches the "limit" number of ids. If _position_ is >= _total_, 1875 this MUST be the empty list. 1877 o *total*: "PositiveInt" (only if requested) The total number of 1878 foos in the results (given the _filter_). This argument MUST be 1879 omitted if the _calculateTotal_ request argument is not "true". 1881 o *limit*: "PositiveInt" (if set by the server) The limit enforced 1882 by the server on the maximum number of results to return. This is 1883 only returned if the server set a limit, or used a different limit 1884 to that given in the request. 1886 The following additional errors may be returned instead of the _Foo/ 1887 query_ response: 1889 "anchorNotFound": An anchor argument was supplied, but it cannot be 1890 found in the results of the query. 1892 "unsupportedSort": The _sort_ is syntactically valid, but includes a 1893 property the server does not support sorting on, or a collation 1894 method it does not recognise. 1896 "unsupportedFilter": The _filter_ is syntactically valid, but the 1897 server cannot process it. If the filter was the result of a user's 1898 search input, the client SHOULD suggest the user simplify their 1899 search. 1901 5.6. /queryChanges 1903 The "Foo/queryChanges" method allows a client to efficiently update 1904 the state of a cached query to match the new state on the server. It 1905 takes the following arguments: 1907 o *accountId*: "Id" The id of the account to use. 1909 o *filter*: "FilterOperator|FilterCondition|null" The filter 1910 argument that was used with _Foo/query_. 1912 o *sort*: "Comparator[]|null" The sort argument that was used with 1913 _Foo/query_. 1915 o *sinceQueryState*: "String" The current state of the query in the 1916 client. This is the string that was returned as the _queryState_ 1917 argument in the _Foo/query_ response with the same sort/filter. 1918 The server will return the changes made to the query since this 1919 state. 1921 o *maxChanges*: "PositiveInt|null" The maximum number of changes to 1922 return in the response. See error descriptions below for more 1923 details. 1925 o *upToId*: "Id|null" The last (highest-index) id the client 1926 currently has cached from the query results. When there are a 1927 large number of results, in a common case the client may have only 1928 downloaded and cached a small subset from the beginning of the 1929 results. If the sort and filter are both only on immutable 1930 properties, this allows the server to omit changes after this 1931 point in the results, which can significantly increase efficiency. 1932 If they are not immutable, this argument is ignored. 1934 o *calculateTotal*: "Boolean" (default: false) Does the client wish 1935 to know the total number of results now in the query? This may be 1936 slow and expensive for servers to calculate, particularly with 1937 complex filters, so clients should take care to only request the 1938 total when needed. 1940 The response has the following arguments: 1942 o *accountId*: "Id" The id of the account used for the call. 1944 o *oldQueryState*: "String" This is the "sinceQueryState" argument 1945 echoed back; the state from which the server is returning changes. 1947 o *newQueryState*: "String" This is the state the query will be in 1948 after applying the set of changes to the old state. 1950 o *total*: "PositiveInt" (only if requested) The total number of 1951 foos in the results (given the _filter_). This argument MUST be 1952 omitted if the _calculateTotal_ request argument is not "true". 1954 o *removed*: "Id[]" The _id_ for every foo that was in the query 1955 results in the old state and is not in the results in the new 1956 state. If the server cannot calculate this exactly, the server 1957 MAY return extra foos in addition that may have been in the old 1958 results but are not in the new results. If the sort and filter 1959 are both only on immutable properties and an _upToId_ is supplied 1960 and exists in the results, any ids that were removed but have a 1961 higher index than _upToId_ SHOULD be omitted. If the _filter_ or 1962 _sort_ includes a mutable property, the server MUST include all 1963 foos in the current results for which this property MAY have 1964 changed. 1966 o *added*: "AddedItem[]" The id and index in the query results (in 1967 the new state) for every foo that has been added to the results 1968 since the old state AND every foo in the current results that was 1969 included in the _removed_ array (due to a filter or sort based 1970 upon a mutable property). If the sort and filter are both only on 1971 immutable properties and an _upToId_ is supplied and exists in the 1972 results, any ids that were added but have a higher index than 1973 _upToId_ SHOULD be omitted. The array MUST be sorted in order of 1974 index, lowest index first. An *AddedItem* object has the 1975 following properties: 1977 * *id*: "Id" 1979 * *index*: "PositiveInt" 1981 The result of this is that if the client has a cached sparse array of 1982 foo ids corresponding to the results in the old state: 1984 fooIds = [ "id1", "id2", null, null, "id3", "id4", null, null, null ] 1986 then if it *splices out* all foos in the removed array: 1988 removed = [ "id2", ... ]; 1989 fooIds => [ "id1", null, null, "id3", "id4", null, null, null ] 1991 and *splices in* (in order) all of the foos in the added array: 1993 added = [{ id: "id5", index: 0, ... }]; 1994 fooIds => [ "id5", "id1", null, null, "id3", "id4", null, null, null ] 1996 and *truncates* or *extends* to the new total length, then the 1997 results will now be in the new state. 1999 The following additional errors may be returned instead of the _Foo/ 2000 queryChanges_ response: 2002 "tooManyChanges": There are more changes than the client's 2003 _maxChanges_ argument. Each item in the removed or added array is 2004 considered as one change. The client may retry with a higher max 2005 changes or invalidate its cache of the query results. 2007 "cannotCalculateChanges": The server cannot calculate the changes 2008 from the queryState string given by the client. Usually due to the 2009 client's state being too old. The client MUST invalidate its cache 2010 of the query results. 2012 5.7. Examples 2014 Suppose we have a type _Todo_ with the following properties: 2016 o *id*: "Id" (immutable; server-set) The id of the object. 2018 o *title*: "String" A brief summary of what is to be done. 2020 o *keywords*: "String[Boolean]" (default: ) A set of keywords that 2021 apply to the todo. The set is represented as an object, with the 2022 keys being the _keywords_. The value for each key in the object 2023 MUST be "true". 2025 o *neuralNetworkTimeEstimation*: "Number" (server-set) The title and 2026 keywords are fed into the server's state-of-the-art neural network 2027 to get an estimation of how long this todo will take, in seconds. 2029 o *subTodoIds*: "Id[]|null" The ids of a list of subtodos to 2030 complete as part of this todo. 2032 Suppose also that all the standard methods are defined for this type, 2033 and the FilterCondition object supports a "hasKeyword" property to 2034 match todos with the given keyword. 2036 A client might want to display the list of todos with either a 2037 "music" keyword or a "video" keyword, so it makes the following 2038 method call: 2040 [[ "Todo/query", { 2041 "accountId": "x", 2042 "filter": { 2043 "operator": "OR", 2044 "conditions": [ 2045 { "hasKeyword": "music" }, 2046 { "hasKeyword": "video" } 2047 ] 2048 }, 2049 "sort": [{ "property": "title" }], 2050 "position": 0, 2051 "limit": 10 2052 }, "0" ], 2053 [ "Todo/get", { 2054 "accountId": "x", 2055 "#ids": { 2056 "resultOf": "0", 2057 "name": "Todo/query", 2058 "path": "/ids" 2059 } 2060 }, "1" ]] 2062 This would query the server for the set of todos with a keyword of 2063 "music", sorted by title, and limited to the first 10 results. It 2064 fetches the full object for each of these Todos using back-references 2065 to reference the result of the query. The response might look 2066 something like: 2068 [[ "Todo/query", { 2069 "accountId": "x", 2070 "queryState": "y13213", 2071 "canCalculateChanges": true, 2072 "position": 0, 2073 "ids": [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" ] 2074 }, "0" ], 2075 [ "Todo/get", { 2076 "accountId": "x", 2077 "state": "10324", 2078 "list": [{ 2079 "id": "a", 2080 "title": "Practise Piano", 2081 "keywords": { 2082 "music": true, 2083 "beethoven": true, 2084 "mozart": true, 2085 "liszt": true, 2086 "rachmaninov": true 2087 }, 2088 "neuralNetworkTimeEstimation": 3600 2089 }, { 2090 "id": "b", 2091 "title": "Listen to Daft Punk", 2092 "keywords": { 2093 "music": true, 2094 "trance": true 2095 }, 2096 "neuralNetworkTimeEstimation": 18000 2097 }, 2098 ... 2099 ] 2100 }, "1" ]] 2102 Now suppose the user adds a keyword "chopin" and removes the keyword 2103 "mozart" from the "Practise Piano" task. The client may send the 2104 whole object to the server, as this is a valid PatchObject: 2106 [[ "Todo/set", { 2107 "accountId": "x", 2108 "ifInState": "10324", 2109 "update": { 2110 "a": { 2111 "id": "a", 2112 "title": "Practise Piano", 2113 "keywords": { 2114 "music": true, 2115 "beethoven": true, 2116 "chopin": true, 2117 "liszt": true, 2118 "rachmaninov": true 2119 }, 2120 "neuralNetworkTimeEstimation": 360 2121 } 2122 } 2123 }, "0" ]] 2125 or it may send a minimal patch: 2127 [[ "Todo/set", { 2128 "accountId": "x", 2129 "ifInState": "10324", 2130 "update": { 2131 "a": { 2132 "keywords/chopin": true, 2133 "keywords/mozart": null 2134 } 2135 } 2136 }, "0" ]] 2138 The effect is exactly the same on the server in either case, and 2139 presuming the server is still in state "10324" it will probably 2140 return success: 2142 [[ "Todo/set", { 2143 "accountId": "x", 2144 "oldState": "10324", 2145 "newState": "10329", 2146 "updated": { 2147 "a": { 2148 "neuralNetworkTimeEstimation": 5400 2149 } 2150 } 2151 }, "0" ]] 2153 The server changed the "neuralNetworkTimeEstimation" property on the 2154 object as part of this change; as this changed in a way _not_ 2155 explicitly requested by the PatchObject sent to the server, it is 2156 returned with the "updated" confirmation. 2158 Let us now add a subtodo to our new "Practice Piano" todo. In this 2159 example we can see the use of a reference to a creation id to allow 2160 us to set a foreign key reference to a record created in the same 2161 request: 2163 [[ "Todo/set", { 2164 "accountId": "x", 2165 "create": { 2166 "k15": { 2167 "title": "Warm up with scales" 2168 } 2169 }, 2170 "update": { 2171 "a": { 2172 "subTodoIds": [ "#k15" ] 2173 } 2174 } 2175 }, "0" ]] 2177 Now, suppose another user deleted the "Listen to Daft Punk" todo. 2178 The first user will receive a push notification (see section 7) with 2179 the changed state string for the "Todo" type. Since the new string 2180 does not match its current state, it knows it needs to check for 2181 updates. It may make a request like: 2183 [[ "Todo/changes", { 2184 "accountId": "x", 2185 "sinceState": "10324", 2186 "maxChanges": 50 2187 }, "0" ], 2188 [ "Todo/queryChanges", { 2189 "accountId": "x", 2190 "filter": { 2191 "operator": "OR", 2192 "conditions": [ 2193 { "hasKeyword": "music" }, 2194 { "hasKeyword": "video" } 2195 ] 2196 }, 2197 "sort": [{ "property": "title" }], 2198 "sinceQueryState": "y13213", 2199 "maxChanges": 50 2200 }, "1" ]] 2202 and receive in response: 2204 [[ "Todo/changes", { 2205 "accountId": "x", 2206 "oldState": "10324", 2207 "newState": "871903", 2208 "hasMoreChanges": false, 2209 "created": [], 2210 "updated": [], 2211 "destroyed": ["b"] 2212 }, "0" ], 2213 [ "Todo/queryChanges", { 2214 "accountId": "x", 2215 "oldQueryState": "y13213", 2216 "newQueryState": "y13218", 2217 "removed": ["b"], 2218 "added": null 2219 }, "1" ]] 2221 Suppose the user has access to another account "y", for example a 2222 team account shared between multiple users. To move an existing Todo 2223 from account "x", the client would call: 2225 [[ "Todo/copy", { 2226 "fromAccountId": "x", 2227 "accountId": "y", 2228 "create": { 2229 "k5122": { 2230 "id": "a" 2231 } 2232 }, 2233 "onSuccessDestroyOriginal": true 2234 }, "0" ]] 2236 The server successfully copies the Todo to a new account (where it 2237 receives a new id) and deletes the original. Due to the implicit 2238 call to "Todo/set", there are two responses to the single method 2239 call, both with the same client id: 2241 [[ "Todo/copy", { 2242 "fromAccountId": "x", 2243 "accountId": "y", 2244 "created": { 2245 "k5122": { 2246 "id": "97" 2247 } 2248 }, 2249 "oldState": "c1d64ecb038c", 2250 "newState": "33844835152b" 2251 }, "0" ], 2252 [ "Todo/set", { 2253 "accountId": "x", 2254 "oldState": "871903", 2255 "newState": "871909", 2256 "destroyed": [ "a" ], 2257 ... 2258 }, "0" ]] 2260 5.8. Proxy considerations 2262 JMAP has been designed to allow an API endpoint to easily proxy 2263 through to one or more JMAP servers. This may be useful for load 2264 balancing, augmenting capabilities, or presenting a single endpoint 2265 to accounts hosted on different JMAP servers (splitting the request 2266 based on each method's "accountId" argument). The proxy need only 2267 understand the general structure of a JMAP Request object, it does 2268 not need to know anything specifically about the methods and 2269 arguments it will pass through to other servers. 2271 If splitting up the methods in a request to call them on different 2272 backend servers, the proxy must do two things to ensure back- 2273 references and creation id references resolve the same as if the 2274 entire request were processed on a single server: 2276 1. It must pass a "createdIds" property with each subrequest. If 2277 this is not given by the client, an empty object should be used 2278 for the first subrequest. The "createdIds" property of each 2279 subresponse should be passed on in the next subrequest. 2281 2. It must resolve back-references to previous method results that 2282 were processed on a different server. This is a relatively 2283 simple syntactic substitution, described in section 3.6. 2285 When splitting a request based on accountId, proxy implementors do 2286 need to be aware of "/copy" methods, that copy between accounts. If 2287 the accounts are on different servers, the proxy will have to 2288 implement this functionality directly. 2290 6. Binary data 2292 Binary data is referenced by a _blobId_ in JMAP, and uploaded/ 2293 downloaded separately to the core API. The blobId solely represents 2294 the raw bytes of data, not any associated metadata such as a file 2295 name or content type. Such metadata is stored alongside the blobId 2296 in the object referencing it. The data represented by a blobId is 2297 immutable. 2299 Any blobId that exists within an account may be used when creating/ 2300 updating another object in that account. For example, an Email type 2301 may have a blobId that represents the [RFC5322] representation of the 2302 message. A client could create a new Email object with an attachment 2303 and use this blobId, in effect attaching the old message to the new 2304 one. Similarly it could attach any existing attachment of an old 2305 message without having to download and upload it again. 2307 When the client uses a blobId in a create/update, the server MAY 2308 assign a new blobId to refer to the same binary data within the new/ 2309 updated object. If it does so, it MUST return any properties that 2310 contain a changed blobId in the created/updated response so the 2311 client gets the new ids. 2313 A blob that is not referenced by a JMAP object (e.g. as a message 2314 attachment) MAY be deleted by the server to free up resources. 2315 Uploads (see below) are initially unreferenced blobs. To ensure 2316 interoperability: 2318 o The server SHOULD use a separate quota for unreferenced blobs to 2319 the accounts's usual quota. This quota SHOULD be separate per 2320 user in the case of shared accounts. 2322 o This quota SHOULD be at least the maximum total size that a single 2323 object can reference on this server. For example, if supporting 2324 JMAP Mail, this should be at least the maximum total attachments 2325 size for a message. 2327 o When an upload would take the user over quota, the server MUST 2328 delete unreferenced blobs in date order, oldest first, until there 2329 is room for the new blob. 2331 o Except where quota restrictions force early deletion, an 2332 unreferenced blob MUST NOT be deleted for at least 1 hour from the 2333 time of upload; if reuploaded, the same blobId MAY be returned, 2334 but this SHOULD reset the expiry time. 2336 o A blob MUST NOT be deleted during the method call which removed 2337 the last reference, so that a client can issue a create and a 2338 destroy that both reference the blob within the same method call. 2340 6.1. Uploading binary data 2342 There is a single endpoint which handles all file uploads for an 2343 account, regardless of what they are to be used for. The JMAP 2344 Session object has an _uploadUrl_ property in [RFC6570] URI Template 2345 (level 1) format, which MUST contain a variable called "accountId". 2346 The client may use this template in combination with an _accountId_ 2347 to get the URL of the file upload resource. 2349 To upload a file, the client submits an authenticated POST request to 2350 the file upload resource. 2352 A successful request MUST return a single JSON object with the 2353 following properties as the response: 2355 o *accountId*: "Id" The id of the account used for the call. 2357 o *blobId*: "Id", The id representing the binary data uploaded. The 2358 data for this id is immutable. The id _only_ refers to the binary 2359 data, not any metadata. 2361 o *type*: "String" The media type of the file (as specified in 2362 [RFC6838], section 4.2) as set in the Content-Type header of the 2363 upload HTTP request. 2365 o *size*: "PositiveInt" The size of the file in octets. 2367 If identical binary content to an existing blob in the account is 2368 uploaded, the existing blobId MAY be returned. 2370 Clients should use the blobId returned in a timely manner. Under 2371 rare circumstances the server may have deleted the blob before the 2372 client uses it; the client should keep a reference to the local file 2373 so it can upload it again in such a situation. 2375 When an HTTP error response is returned to the client, the server 2376 SHOULD return a JSON "problem details" object as the response body, 2377 as per [RFC7807]. 2379 As access controls are often determined by the object holding the 2380 reference to a blob, unreferenced blobs MUST only be accessible to 2381 the uploader, even in shared accounts. 2383 6.2. Downloading binary data 2385 The JMAP Session object has a _downloadUrl_ property, which is in 2386 [RFC6570] URI Template (level 1) format. The URL MUST contain 2387 variables called "accountId", "blobId", "type" and "name". 2389 To download a file, the client makes an authenticated GET request to 2390 the download URL with the appropriate variables substituted in: 2392 o "accountId": The id of the account to which the record with the 2393 blobId belongs. 2395 o "blobId": The blobId representing the data of the file to 2396 download. 2398 o "type": The type for the server to set in the "Content-Type" 2399 header of the response; the blobId only represents the binary data 2400 and does not have a content-type innately associated with it. 2402 o "name": The name for the file; the server MUST return this as the 2403 filename if it sets a "Content-Disposition" header. 2405 As the data for a particular blobId is immutable, and thus the 2406 response in the generated download URL is too, implementors are 2407 recommended to set long cache times for successful responses, for 2408 example "Cache-Control: private, max-age=31536000". 2410 When an HTTP error response is returned to the client, the server 2411 SHOULD return a JSON "problem details" object as the response body, 2412 as per [RFC7807]. 2414 6.3. Blob/copy 2416 Binary data may be copied *between* two different accounts using the 2417 _Blob/copy_ method, rather than having to download then reupload on 2418 the client. 2420 The _Blob/copy_ method takes the following arguments: 2422 o *fromAccountId*: "Id" The id of the account to copy blobs from. 2424 o *accountId*: "Id" The id of the account to copy blobs to. 2426 o *blobIds*: "Id[]" A list of ids of blobs to copy to the other 2427 account. 2429 The response has the following arguments: 2431 o *fromAccountId*: "Id" The id of the account emails were copied 2432 from. 2434 o *accountId*: "Id" The id of the account emails were copied to. 2436 o *copied*: "Id[Id]|null" A map of the blobId in the _fromAccount_ 2437 to the id for the blob in the _toAccount_, or "null" if none were 2438 successfully copied. 2440 o *notCopied*: "Id[SetError]|null" A map of blobId to a SetError 2441 object for each blob that failed to be copied, "null" if none. 2443 The *SetError* may be any of the standard set errors that may be 2444 returned for a _create_. In addition, the "notFound" SetError error 2445 may be returned if the blobId to be copied cannot be found. 2447 The following additional errors may be returned instead of the _Blob/ 2448 copy_ response: 2450 "fromAccountNotFound": The _fromAccountId_ included with the request 2451 does not correspond to a valid account. 2453 7. Push 2455 Push notifications allow clients to efficiently update (almost) 2456 instantly to stay in sync with data changes on the server. In JMAP, 2457 push notifications occur out-of-band (i.e. not over the same 2458 connection as API exchanges), so that they can make use of efficient 2459 native push mechanisms on different platforms. 2461 The general model for push is simple and sends minimal data over the 2462 push channel. The format allows multiple changes to be coalesced 2463 into a single push update, and the frequency of pushes to be rate 2464 limited by the server. It doesn't matter if some push events are 2465 dropped before they reach the client; it will still get all changes 2466 next time it syncs. 2468 7.1. The StateChange object 2470 When something changes on the server, the server pushes a 2471 *StateChange* object to the client. A *StateChange* object has the 2472 following properties: 2474 o *changed*: "Id[TypeState]" A map of _account id_ to an object 2475 encoding the state of data types that have changed for that 2476 account since the last push event, for each of the accounts to 2477 which the user has access and for which something has changed. A 2478 *TypeState* object is a map. The keys are the type name "Foo" 2479 (e.g. "Mailbox" or "Email"), and the value is the _state_ 2480 property that would currently be returned by a call to _Foo/get_. 2481 The client can compare the new state strings with its current 2482 values to see whether it has the current data for these types. If 2483 not, the changes can then be efficiently fetched in a single 2484 standard API request (using the _/changes_ type methods). 2486 7.1.1. Example 2488 In this example, the server has amalgamated a few changes together 2489 across two different accounts the user has access to, before pushing 2490 the following StateChange object to the client: 2492 { 2493 "changed": { 2494 "a3123": { 2495 "Email": "d35ecb040aab", 2496 "EmailDelivery": "428d565f2440", 2497 "CalendarEvent": "87accfac587a" 2498 }, 2499 "a43461d": { 2500 "Mailbox": "0af7a512ce70", 2501 "CalendarEvent": "7a4297cecd76" 2502 } 2503 } 2504 } 2506 The client can compare the state strings with its current state for 2507 the Email, CalendarEvent etc. object types in the appropriate 2508 accounts to see if it needs to fetch changes. If the client is 2509 itself making changes, it may receive a StateChange object while the 2510 /set API call is in flight. It can wait until the call completes and 2511 then compare if the new state string after the /set is the same as 2512 was pushed in the StateChange object; if so, it does not need to 2513 waste a request asking for changes it already knows. 2515 7.2. PushSubscription 2517 A push subscription is a message delivery context established between 2518 the client and a push service. A *PushSubscription* object has the 2519 following properties: 2521 o *id*: "Id" (immutable; server-set) The id of the push 2522 subscription. 2524 o *deviceClientId*: "String" (immutable) An id that uniquely 2525 identifies the client + device it is running on. The purpose of 2526 this is to allow clients to identify which PushSubscription 2527 objects they created even if they lose their local state, so they 2528 can revoke or update them. This string MUST be different on 2529 different devices, and be different from other vendors. It SHOULD 2530 be easy to re-generate, not depend on persisted state. A secure 2531 hash that includes both a device id and vendor id is one way this 2532 could be achieved. 2534 o *url*: "String" (immutable) An absolute URL where the JMAP server 2535 will POST the data for the push message. This MUST begin with 2536 "https://". 2538 o *keys*: "Object|null" (immutable) Client-generated encryption 2539 keys. If supplied the server MUST use them as specified in 2540 [RFC8291] to encrypt all data sent to the push subscription. The 2541 object MUST have the following properties: 2543 * *p256dh*: the P-256 ECDH Diffie-Hellman public key as described 2544 in [RFC8291], encoded in URL-safe Base64 representation as 2545 defined in [RFC4648]. 2547 * *auth*: the authentication secret as described in [RFC8291], 2548 encoded in URL-safe Base64 representation as defined in 2549 [RFC4648]. 2551 o *expires*: "UTCDate|null" The time this push subscription expires. 2552 If specified, the JMAP server MUST NOT make further requests to 2553 this resource after this time. It MAY automatically destroy the 2554 push subscription at or after this time. The server MAY choose to 2555 set an expiry if none is given by the client, or modify the expiry 2556 time given by the client to a shorter duration. 2558 o *types*: "String[]|null" A list of types the client is interested 2559 in (using the same names as the keys in the _TypeState_ object 2560 defined in the previous section). Push events will only be sent 2561 if the data for one of these types changes. Other types are 2562 omitted from the TypeState object. If "null", changes will be 2563 pushed for all types. 2565 Clients may create a push subscription on the JMAP server, which will 2566 then make a POST request to the associated push endpoint whenever an 2567 event occurs. 2569 The POST request MUST have a content type of "application/json" and 2570 contain the UTF-8 JSON encoded _StateChange_ object as the body. The 2571 request MUST have a "TTL" header, and MAY have "Urgency" and/or 2572 "Topic" headers, as specified in section 5 of [RFC8030]. The server 2573 is expected to understand and handle HTTP status responses in a 2574 reasonable manner. See the security considerations in section 8.6 2575 for a discussion of the risks in connecting to unknown servers. 2577 The use of this push endpoint conforms with the use of a push 2578 endpoint by an Application Server as defined in [RFC8030]. A client 2579 MAY use the rest of [RFC8030] in combination with its own Push Server 2580 to form a complete end-to-end solution, or MAY rely on alternative 2581 mechanisms to ensure the delivery of the pushed data after it leaves 2582 the JMAP server. 2584 The push subscription is tied to the credentials used to authenticate 2585 the API request that created it. Should these credentials expire or 2586 be revoked, the push subscription MUST be destroyed by the JMAP 2587 server. 2589 When these credentials have their own expiry (i.e. it is a session 2590 with a timeout), the server SHOULD NOT set or bound the expiry time 2591 for the push subscription given by the client, but MUST expire it 2592 when the session expires. 2594 When these credentials are not time bounded (e.g. [RFC7617] Basic 2595 Authentication), the server SHOULD set an expiry time for the push 2596 subscription if none given, and limit the expiry time if set too far 2597 in the future. This maximum expiry time MUST be at least 48 hours in 2598 the future and SHOULD be at least 7 days in the future. An app 2599 running on a mobile device may only be able to refresh the push 2600 subscription lifetime when it is in the foreground, and so this gives 2601 a reasonable timeframe to allow this to happen. 2603 In the case of separate access and refresh credentials, as in 2604 [RFC6749] Oauth 2.0, the server SHOULD tie the push subscription to 2605 the validity of the refresh token rather than the access token, and 2606 behave according to whether this is time-limited or not. 2608 7.2.1. PushSubscription/get 2610 Standard _/get_ method, except it does *not* take or return an 2611 _accountId_ argument, as push subscriptions are not tied to specific 2612 accounts. It also does *not* return a _state_ argument. The _ids_ 2613 argument may be "null" to fetch all at once. 2615 As the _url_ and _keys_ properties may contain data that is private 2616 to a particular device, the values for these properties MUST NOT be 2617 returned. If the _properties_ argument is "null" or omitted, the 2618 server MUST default to all properties excluding these two. If one of 2619 them is explicitly requested, the method call MUST be rejected with a 2620 "forbidden" error. 2622 7.2.2. PushSubscription/set 2624 Standard _/set_ method except it does *not* take or return an 2625 _accountId_ argument, as push subscriptions are not tied to specific 2626 accounts. It also does *not* take an _ifInState_ argument or return 2627 _oldState_ or _newState_ arguments. 2629 The _url_ and _keys_ properties are immutable; if the client wishes 2630 to change these, it must destroy the current push subscription and 2631 create a new one. 2633 The client may update the _expires_ property to extend (or, less 2634 commonly, shorten) the lifetime of a push subscription. The server 2635 MAY modify the proposed new expiry time to enforce server-defined 2636 limits. 2638 Clients SHOULD NOT update or destroy a push subscription that they 2639 did not create (i.e. has a _deviceClientId_ that they do not 2640 recognise). 2642 7.2.3. Example 2644 A client with deviceClientId "a889-ffea-910" fetches the set of push 2645 subscriptions currently on the server, making an API request with: 2647 [[ "PushSubscription/get", { 2648 "ids": null 2649 }, "0" ]] 2651 Which returns: 2653 [[ "PushSubscription/get", { 2654 "list": [{ 2655 "id": "e50b2c1d-9553-41a3-b0a7-a7d26b599ee1", 2656 "deviceClientId": "b37ff8001ca0", 2657 "expires": "2018-01-31T00:13:21Z", 2658 "types": [ "Todo" ] 2659 }, { 2660 "id": "f2d0aab5-e976-4e8b-ad4b-b380a5b987e4", 2661 "deviceClientId": "8980fc", 2662 "expires": "2018-02-12T05:55:00Z", 2663 "types": [ "Mailbox", "Email", "EmailDelivery" ] 2664 }], 2665 "notFound": [] 2666 }, "0" ]] 2668 Since neither of the returned push subscription objects have the 2669 client's deviceClientId, it knows it does not have a current push 2670 subscription active on the server. So it creates one, sending this 2671 request: 2673 [[ "PushSubscription/set", { 2674 "create": { 2675 "4f29": { 2676 "deviceClientId": "a889-ffea-910", 2677 "url": "https://example.com/push/?device=8980fc&client=12c6d086", 2678 "types": null 2679 } 2680 } 2681 }, "0" ]] 2683 The server creates the push subscription but limits the expiry time 2684 to 7 days in the future, returning this response: 2686 [[ "PushSubscription/set", { 2687 "created": { 2688 "4f29": { 2689 "id": "043dcfa4-1dd4-41ef-9156-2c89b3b19c60", 2690 "keys": null, 2691 "expires": "2018-07-13T02:14:29Z" 2692 } 2693 } 2694 }, "0" ]] 2696 Two days later, the client updates the subscription to extend its 2697 lifetime, sending this request: 2699 [[ "PushSubscription/set", { 2700 "update": { 2701 "043dcfa4-1dd4-41ef-9156-2c89b3b19c60": { 2702 "expires": "2018-08-13T00:00:00Z" 2703 } 2704 } 2705 }, "0" ]] 2707 The server extends the expiry time, but only again to its maximum 2708 limit of 7 days in the future, returning this response: 2710 [[ "PushSubscription/set", { 2711 "updated": { 2712 "043dcfa4-1dd4-41ef-9156-2c89b3b19c60": { 2713 "expires": "2018-07-16T02:22:50Z" 2714 } 2715 } 2716 }, "0" ]] 2718 7.3. Event Source 2720 Clients that can hold open TCP connections can connect directly to 2721 the JMAP server to receive push notifications via a "text/event- 2722 stream" resource, as described in . This is a long running HTTP request down which the 2724 server can push data. 2726 When a change occurs in the data on the server, it pushes an event 2727 called *state* to any connected clients, with the _StateChange_ 2728 object as the data. 2730 The server SHOULD also send a new event id that encodes the entire 2731 server state visible to the user immediately after sending a _state_ 2732 event. When a new connection is made to the event-source endpoint, a 2733 client following the server-sent events specification [1] will send a 2734 Last-Event-ID HTTP header with the last id it saw, which the server 2735 can use to work out whether the client has missed some changes. If 2736 so, it SHOULD send these changes immediately on connection. 2738 The client may add a query parameter called "types", with the value 2739 being a comma-separated list of type names. If present, the server 2740 MUST only push changes for the types in this list. If omitted, 2741 changes to all types are pushed. 2743 The client may add a query parameter called "closeafter" with value 2744 "state" to the event-source resource URL when requesting the event- 2745 source resource. If set, the server MUST end the HTTP response after 2746 pushing a _state_ event. This can be used by clients in environments 2747 where buffering proxies prevent the pushed data from arriving 2748 immediately, or indeed at all, when operating in the usual mode. 2750 The client may add a query parameter called "ping", with a positive 2751 integer value representing a length of time in seconds, e.g. 2752 "ping=300". If set, the server MUST send an event called *ping* 2753 whenever this time elapses since the previous event was sent. This 2754 MUST NOT set a new event id. 2756 The server MAY modify the ping interval given as a query parameter to 2757 be subject to a minimum and/or maximum value. For interoperability, 2758 servers MUST NOT have a minimum allowed value higher than 30 or a 2759 maximum allowed value less than 300. 2761 The data for the ping event MUST be a JSON object containing an 2762 _interval_ property, the value (type "PositiveInt") being the 2763 interval in seconds the server is using to send pings (this may be 2764 different to the requested value if the server clamped it to be 2765 within a min/max value). 2767 Clients can monitor for the _ping_ event to help determine when the 2768 closeafter mode may be required. 2770 Refer to the JMAP Session resource in section 2 for details on how to 2771 get the URL for the event-source resource. Requests to the resource 2772 MUST be authenticated. 2774 A client MAY hold open multiple connections to the event-source 2775 resource, although it SHOULD try to use a single connection for 2776 efficiency. 2778 8. Security considerations 2780 8.1. Transport confidentiality 2782 All HTTP requests MUST use [RFC8446] TLS (https) transport to ensure 2783 the confidentiality of data sent and received via JMAP. Clients MUST 2784 validate TLS certificate chains to protect against man-in-the-middle 2785 attacks. 2787 8.2. Authentication scheme 2789 A number of HTTP authentication schemes have been standardised 2790 (). Servers should take care to assess the security 2792 characteristics of different schemes in relation to their needs when 2793 deciding what to implement. 2795 If offering the Basic authentication scheme, services are strongly 2796 recommended to not allow a user's regular password but require 2797 generation of a unique "app password" via some external mechanism for 2798 each client they wish to connect. This allows connections from 2799 different devices to be differentiated by the server, and access to 2800 be individually revoked. 2802 8.3. Service autodiscovery 2804 Unless secured by something like DNSSEC, autodiscovery of server 2805 details is vulnerable to a DNS poisoning attack leading to the client 2806 talking to an attacker's server instead of the real JMAP server. The 2807 attacker may then man-in-the-middle requests and depending on the 2808 authentication scheme, steal credentials to generate its own 2809 requests. 2811 Clients that do not support SRV lookups are likely to try just using 2812 the "/.well-known/jmap" path directly against the domain of the 2813 username over HTTPS. Servers SHOULD ensure this path resolves or 2814 redirects to the correct JMAP Session resource to allow this to work. 2816 If this is not feasible, servers MUST ensure this path cannot be 2817 controlled by an attacker, as again it may be used to steal 2818 credentials. 2820 8.4. JSON parsing 2822 The security considerations of [RFC8259] apply to the use of JSON as 2823 the data interchange format. 2825 8.5. Denial of service 2827 A small request may result in a very large response, and require 2828 considerable work on the server if resource limits are not enforced. 2829 JMAP provides mechanisms for advertising and enforcing a wide variety 2830 of limits for mitigating this threat, including limits on number of 2831 objects fetched in a single method call, number of methods in a 2832 single request, number of concurrent requests, etc. 2834 JMAP servers MUST implement sensible limits to mitigate against 2835 resource exhaustion attacks. 2837 8.6. Connection to unknown push server 2839 When a push subscription is registered, the application server will 2840 make POST requests to the given URL. There are a number of security 2841 considerations that MUST be considered when implementing this. The 2842 server MUST ensure the URL is externally resolvable to avoid server- 2843 side request forgery, where the server makes a request to a resource 2844 on its internal network. 2846 A malicious client may use the push subscription to attempt to flood 2847 a 3rd party server with requests, creating a denial of service attack 2848 and masking the attacker's true identity. There is no guarantee the 2849 URL that was given to the JMAP server is actually a valid push 2850 server. The JMAP server MUST therefore be defensive in its handling 2851 of error responses when it tries to make a request to the given URL. 2852 Any permanent HTTP error MUST destroy the push subscription and 2853 prevent further attempts to send requests to that server. A "429" 2854 (Too Many Requests) response MUST cause the JMAP server to reduce the 2855 frequency of pushes; the JMAP push structure allows multiple to be 2856 coalesced into a single minimal object that will still ensure the 2857 client comes fully up to date when it resyncs. 2859 8.7. Push encryption 2861 When data changes, a small object is pushed with the new state 2862 strings for the types that have changed. While the data here is 2863 minimal, a passive man-in-the-middle attacker may be able to gain 2864 useful information. To ensure confidentiality, if the push is sent 2865 via a third party outside of the control of the client and JMAP 2866 server the client MUST specify encryption keys when establishing the 2867 PushSubscription. 2869 The privacy and security considerations of [RFC8030] and [RFC8291] 2870 also all apply to the use of the PushSubscription mechanism. 2872 9. IANA considerations 2874 9.1. Assignment of jmap service name 2876 IANA will assign the 'jmap' service name in the 'Service Name and 2877 Transport Protocol Port Number Registry' [RFC6335]. 2879 Service Name: jmap 2881 Transport Protocol(s): tcp 2883 Assignee: IESG 2885 Contact: IETF Chair 2887 Description: JSON Meta Application Protocol 2889 Reference: this document 2891 Assignment Notes: this service name was previously assigned under the 2892 name _JSON Mail Access Protocol_. This will be de-assigned and re- 2893 assigned with the approval of the previous assignee. 2895 9.2. Registration of well-known URI suffix for JMAP 2897 IANA will register the following well-known URI suffix for JMAP as 2898 described in [RFC5785]: 2900 URI Suffix: jmap 2902 Change Controller: IETF 2904 Specification Document: this document, section 2.2. 2906 9.3. Registration of the jmap URN sub-namespace 2908 IANA will register the following URN sub-namespace in the "IETF URN 2909 Sub-namespace for Registered Protocol Parameter Identifiers" registry 2910 as described in [RFC3553]. 2912 Registered Parameter Identifier: jmap 2914 Reference: this document, next section 2916 IANA Registry Reference: {insert IANA registry URL for registry in 2917 next section, upon approval} 2919 9.4. Creation of "JMAP Capabilities" registry 2921 IANA will create a registry for JMAP capabilities as described in 2922 section 2. JMAP capabilities are advertised in the _capabilities_ 2923 property of the JMAP Session resource. They are used to extend the 2924 functionality of a JMAP server. A capability is referenced by a URI. 2925 The JMAP capability URI can be a URN starting with 2926 "urn:ietf:params:jmap:" plus a unique suffix which is the index value 2927 in the jmap URN sub-namespace. Registration of a JMAP capability 2928 with another form of URI has no impact on the jmap URN sub-namespace. 2930 This registry follows the expert review process unless the "intended 2931 use" field is _common_ or _placeholder_ in which case registration 2932 follows the specification required process. 2934 A JMAP capability registration can have an intended use of _common_, 2935 _placeholder_, _limited_, or _obsolete_. IANA will list common use 2936 registrations prominently and separately from those with other 2937 intended use values. 2939 The JMAP capability registration procedure is not a formal standards 2940 process, but rather an administrative procedure intended to allow 2941 community comment and sanity checking without excessive time delay. 2943 A _placeholder_ registration reserves part of the jmap urn namespace 2944 for another purpose but is typically not included in the 2945 _capabilities_ property of the JMAP Session resource. 2947 9.4.1. Preliminary community review 2949 Notice of a potential JMAP common use registration SHOULD be sent to 2950 the jmap@ietf.org mailing list for review. This mailing list is 2951 appropriate to solicit community feedback on a proposed JMAP 2952 capability. Registrations that are not intended for common use MAY 2953 be sent to the list for review as well; doing so is entirely 2954 OPTIONAL, but is encouraged. 2956 The intent of the public posting to this list is to solicit comments 2957 and feedback on the choice of capability name, the unambiguity of the 2958 specification document, and a review of any interoperability or 2959 security considerations. The submitter may submit a revised 2960 registration proposal or abandon the registration completely and at 2961 any time. 2963 9.4.2. Submit request to IANA 2965 Registration requests can be sent to iana@iana.org. 2967 9.4.3. Designated expert review 2969 For a limited use registration, the designated expert's (DE) primary 2970 concern is preventing name collisions and encouraging the submitter 2971 to document security and privacy considerations; a published 2972 specification is not required. For a common use registration, the DE 2973 is expected to confirm that suitable documentation as described in 2974 [RFC8126], Section 4.6, is available. The DE should also verify the 2975 capability does not conflict with work that is active or already 2976 published within the IETF. 2978 Before a period of 30 days has passed, the DE will either approve or 2979 deny the registration request and publish a notice of the decision to 2980 the JMAP WG mailing list or its successor, as well as informing IANA. 2981 A denial notice must be justified by an explanation, and in the cases 2982 where it is possible, concrete suggestions on how the request can be 2983 modified so as to become acceptable should be provided. 2985 9.4.4. Change procedures 2987 Once a JMAP capability has been published by the IANA, the change 2988 controller may request a change to its definition. The same 2989 procedure that would be appropriate for the original registration 2990 request is used to process a change request. 2992 JMAP capability registrations may not be deleted; capabilities that 2993 are no longer believed appropriate for use can be declared obsolete 2994 by a change to their "intended use" field; such capabilities will be 2995 clearly marked in the lists published by the IANA. 2997 Significant changes to a capability's definition should be requested 2998 only when there are serious omissions or errors in the published 2999 specification. When review is required, a change request may be 3000 denied if it renders entities that were valid under the previous 3001 definition invalid under the new definition. 3003 The owner of a JMAP capability may pass responsibility to another 3004 person or agency by informing the IANA; this can be done without 3005 discussion or review. 3007 The IESG may reassign responsibility for a JMAP capability. The most 3008 common case of this will be to enable changes to be made to 3009 capabilities where the author of the registration has died, moved out 3010 of contact, or is otherwise unable to make changes that are important 3011 to the community. 3013 9.4.5. JMAP Capabilities registry template: 3015 Capability name: (see capability property in section 2) 3017 Specification document: 3019 Intended use: (one of common, limited, or obsolete) 3021 Change controller: (_IETF_ for standards-track/BCP RFCs) 3023 Security and privacy considerations: 3025 9.4.6. Initial registration for JMAP core 3027 Capability Name: "urn:ietf:params:jmap:core" 3029 Specification document: this document, section 2 3031 Intended use: common 3033 Change Controller: IETF 3035 Security and privacy considerations: this document, section 8. 3037 9.4.7. Registration for JMAP error placeholder in JMAP capabilities 3038 registry 3040 Capability Name: "urn:ietf:params:jmap:error:" 3042 Specification document: this document, next section. 3044 Intended use: placeholder 3046 Change Controller: IETF 3048 Security and privacy considerations: this document, section 8. 3050 9.5. Creation of "JMAP Error Codes" registry 3052 IANA will create a registry for JMAP error codes. JMAP error codes 3053 appear in the "type" member of a JSON problem details object (as 3054 described in section 3.5.1), in the "type" member in a JMAP error 3055 object (as described in section 3.5.2), or the "type" member of a 3056 JMAP method-specific error object (such as SetError in section 5.3). 3057 When used in a problem details object, the prefix 3058 'urn:ietf:params:jmap:error:' is always included, and when used in 3059 JMAP objects, the prefix is always omitted. 3061 This registry follows the expert review process. Preliminary 3062 community review for this registry follows the same procedures as the 3063 JMAP capabilities registry but is optional. The change procedures 3064 for this registry are the same as the change procedures for the JMAP 3065 capabilities registry. 3067 9.5.1. Designated expert review 3069 The designated expert should review the following aspects of the 3070 registration: 3072 1. Verify the error code does not conflict with existing names. 3074 2. Verify the error code follows the syntax limitations (does not 3075 require URI encoding). 3077 3. Encourage the error code to follow the naming convention of 3078 previously registered errors. 3080 4. Encourage description of client behaviors that are recommended in 3081 response to the error code. These may distinguish the error code 3082 from other error codes. 3084 5. Encourage description of when the server should issue the error 3085 as opposed to some other error code. 3087 6. Encourage the submitter to note any security considerations 3088 associated with the error, if any. For example, an error code 3089 that might disclose existence of data the authenticated user does 3090 not have permission to know about. 3092 Steps 3-6 are meant to promote a higher-quality registry. However, 3093 the expert is encouraged to approve any registration that would not 3094 actively harm JMAP interoperability to make this a relatively 3095 lightweight process. 3097 9.5.2. JMAP Error Codes registry template: 3099 JMAP Error Code: 3101 Intended use: (one of _common_, _limited_, _obsolete_) 3102 Change Controller: (_IETF_ for standards-track/BCP RFCs) 3104 Description or Reference: 3106 9.5.3. Initial JMAP Error Codes registry 3108 +------------------------------+---------+------------+-------------+ 3109 | JMAP Error Code | Intende | Change | Description | 3110 | | d Use | Controller | or | 3111 | | | | Reference | 3112 +------------------------------+---------+------------+-------------+ 3113 | accountNotFound | common | IETF | RFC XXXX | 3114 | | | | section | 3115 | | | | 3.5.2 | 3116 | accountNotSupportedByMethod | common | IETF | RFC XXXX | 3117 | | | | section | 3118 | | | | 3.5.2 | 3119 | accountReadOnly | common | IETF | RFC XXXX | 3120 | | | | section | 3121 | | | | 3.5.2 | 3122 | anchorNotFound | common | IETF | RFC XXXX | 3123 | | | | section 5.5 | 3124 | alreadyExists | common | IETF | RFC XXXX | 3125 | | | | section 5.4 | 3126 | cannotCalculateChanges | common | IETF | RFC XXXX | 3127 | | | | sections | 3128 | | | | 5.2 and 5.6 | 3129 | forbidden | common | IETF | RFC XXXX | 3130 | | | | sections | 3131 | | | | 3.5.2, 5.3, | 3132 | | | | and 7.2.1 | 3133 | fromAccountNotFound | common | IETF | RFC XXXX | 3134 | | | | sections | 3135 | | | | 5.4 and 6.3 | 3136 | fromAccountNotSupportedByMet | common | IETF | RFC XXXX | 3137 | hod | | | section 5.4 | 3138 | invalidArguments | common | IETF | RFC XXXX | 3139 | | | | section | 3140 | | | | 3.5.2 | 3141 | invalidPatch | common | IETF | RFC XXXX | 3142 | | | | section 5.3 | 3143 | invalidProperties | common | IETF | RFC XXXX | 3144 | | | | section 5.3 | 3145 | notFound | common | IETF | RFC XXXX | 3146 | | | | section 5.3 | 3147 | notJSON | common | IETF | RFC XXXX | 3148 | | | | section | 3149 | | | | 3.5.1 | 3150 | notRequest | common | IETF | RFC XXXX | 3151 | | | | section | 3152 | | | | 3.5.1 | 3153 | overQuota | common | IETF | RFC XXXX | 3154 | | | | section 5.3 | 3155 | rateLimit | common | IETF | RFC XXXX | 3156 | | | | section 5.3 | 3157 | requestTooLarge | common | IETF | RFC XXXX | 3158 | | | | sections | 3159 | | | | 5.1 and 5.3 | 3160 | invalidResultReference | common | IETF | RFC XXXX | 3161 | | | | section | 3162 | | | | 3.5.2 | 3163 | serverFail | common | IETF | RFC XXXX | 3164 | | | | section | 3165 | | | | 3.5.2 | 3166 | serverPartialFail | limited | IETF | RFC XXXX | 3167 | | | | section | 3168 | | | | 3.5.2 | 3169 | serverUnavailable | common | IETF | RFC XXXX | 3170 | | | | section | 3171 | | | | 3.5.2 | 3172 | singleton | common | IETF | RFC XXXX | 3173 | | | | section 5.3 | 3174 | stateMismatch | common | IETF | RFC XXXX | 3175 | | | | section 5.3 | 3176 | tooLarge | common | IETF | RFC XXXX | 3177 | | | | section 5.3 | 3178 | tooManyChanges | common | IETF | RFC XXXX | 3179 | | | | section 5.6 | 3180 | unknownCapability | common | IETF | RFC XXXX | 3181 | | | | section | 3182 | | | | 3.5.1 | 3183 | unknownMethod | common | IETF | RFC XXXX | 3184 | | | | section | 3185 | | | | 3.5.2 | 3186 | unsupportedFilter | common | IETF | RFC XXXX | 3187 | | | | section 5.5 | 3188 | unsupportedSort | common | IETF | RFC XXXX | 3189 | | | | section 5.5 | 3190 | willDestroy | common | IETF | RFC XXXX | 3191 | | | | section 5.3 | 3192 +------------------------------+---------+------------+-------------+ 3194 10. References 3196 10.1. Normative References 3198 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 3199 Requirement Levels", BCP 14, RFC 2119, 3200 DOI 10.17487/RFC2119, March 1997, 3201 . 3203 [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for 3204 specifying the location of services (DNS SRV)", RFC 2782, 3205 DOI 10.17487/RFC2782, February 2000, 3206 . 3208 [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: 3209 Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, 3210 . 3212 [RFC3553] Mealling, M., Masinter, L., Hardie, T., and G. Klyne, "An 3213 IETF URN Sub-namespace for Registered Protocol 3214 Parameters", BCP 73, RFC 3553, DOI 10.17487/RFC3553, June 3215 2003, . 3217 [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 3218 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 3219 2003, . 3221 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data 3222 Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, 3223 . 3225 [RFC4790] Newman, C., Duerst, M., and A. Gulbrandsen, "Internet 3226 Application Protocol Collation Registry", RFC 4790, 3227 DOI 10.17487/RFC4790, March 2007, 3228 . 3230 [RFC5051] Crispin, M., "i;unicode-casemap - Simple Unicode Collation 3231 Algorithm", RFC 5051, DOI 10.17487/RFC5051, October 2007, 3232 . 3234 [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, 3235 DOI 10.17487/RFC5322, October 2008, 3236 . 3238 [RFC5785] Nottingham, M. and E. Hammer-Lahav, "Defining Well-Known 3239 Uniform Resource Identifiers (URIs)", RFC 5785, 3240 DOI 10.17487/RFC5785, April 2010, 3241 . 3243 [RFC6186] Daboo, C., "Use of SRV Records for Locating Email 3244 Submission/Access Services", RFC 6186, 3245 DOI 10.17487/RFC6186, March 2011, 3246 . 3248 [RFC6335] Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S. 3249 Cheshire, "Internet Assigned Numbers Authority (IANA) 3250 Procedures for the Management of the Service Name and 3251 Transport Protocol Port Number Registry", BCP 165, 3252 RFC 6335, DOI 10.17487/RFC6335, August 2011, 3253 . 3255 [RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M., 3256 and D. Orchard, "URI Template", RFC 6570, 3257 DOI 10.17487/RFC6570, March 2012, 3258 . 3260 [RFC6749] Hardt, D., Ed., "The OAuth 2.0 Authorization Framework", 3261 RFC 6749, DOI 10.17487/RFC6749, October 2012, 3262 . 3264 [RFC6764] Daboo, C., "Locating Services for Calendaring Extensions 3265 to WebDAV (CalDAV) and vCard Extensions to WebDAV 3266 (CardDAV)", RFC 6764, DOI 10.17487/RFC6764, February 2013, 3267 . 3269 [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type 3270 Specifications and Registration Procedures", BCP 13, 3271 RFC 6838, DOI 10.17487/RFC6838, January 2013, 3272 . 3274 [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., 3275 "JavaScript Object Notation (JSON) Pointer", RFC 6901, 3276 DOI 10.17487/RFC6901, April 2013, 3277 . 3279 [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 3280 Protocol (HTTP/1.1): Message Syntax and Routing", 3281 RFC 7230, DOI 10.17487/RFC7230, June 2014, 3282 . 3284 [RFC7235] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 3285 Protocol (HTTP/1.1): Authentication", RFC 7235, 3286 DOI 10.17487/RFC7235, June 2014, 3287 . 3289 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 3290 DOI 10.17487/RFC7493, March 2015, 3291 . 3293 [RFC7617] Reschke, J., "The 'Basic' HTTP Authentication Scheme", 3294 RFC 7617, DOI 10.17487/RFC7617, September 2015, 3295 . 3297 [RFC7807] Nottingham, M. and E. Wilde, "Problem Details for HTTP 3298 APIs", RFC 7807, DOI 10.17487/RFC7807, March 2016, 3299 . 3301 [RFC8030] Thomson, M., Damaggio, E., and B. Raymor, Ed., "Generic 3302 Event Delivery Using HTTP Push", RFC 8030, 3303 DOI 10.17487/RFC8030, December 2016, 3304 . 3306 [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for 3307 Writing an IANA Considerations Section in RFCs", BCP 26, 3308 RFC 8126, DOI 10.17487/RFC8126, June 2017, 3309 . 3311 [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 3312 Interchange Format", STD 90, RFC 8259, 3313 DOI 10.17487/RFC8259, December 2017, 3314 . 3316 [RFC8291] Thomson, M., "Message Encryption for Web Push", RFC 8291, 3317 DOI 10.17487/RFC8291, November 2017, 3318 . 3320 [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol 3321 Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, 3322 . 3324 10.2. URIs 3326 [1] https://html.spec.whatwg.org/multipage/server-sent-events.html 3328 Authors' Addresses 3329 Neil Jenkins 3330 FastMail 3331 PO Box 234, Collins St West 3332 Melbourne VIC 8007 3333 Australia 3335 Email: neilj@fastmailteam.com 3336 URI: https://www.fastmail.com 3338 Chris Newman 3339 Oracle 3340 440 E. Huntington Dr., Suite 400 3341 Arcadia CA 91006 3342 United States of America 3344 Email: chris.newman@oracle.com