Authzed Watch API

Stream real-time relationship change updates

OpenAPI Specification

authzed-watch-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Authzed SpiceDB Permissions Experimental Watch API
  description: SpiceDB Permissions API — gRPC and HTTP/JSON interfaces for writing schemas, managing relationship tuples, and executing permission checks using a Zanzibar-inspired graph model. Supports CheckPermission, LookupResources, LookupSubjects, WriteRelationships, ReadRelationships, DeleteRelationships, WriteSchema, ReadSchema, and streaming Watch operations.
  version: '1.0'
  contact:
    name: Authzed, Inc.
    url: https://github.com/authzed/api
    email: support@authzed.com
  license:
    name: Apache 2.0 License
    url: https://github.com/authzed/api/blob/main/LICENSE
servers:
- url: https://grpc.authzed.com
  description: Authzed Cloud primary endpoint
- url: https://app.authzed.com
  description: Authzed Cloud management endpoint
security:
- BearerAuth: []
tags:
- name: Watch
  description: Stream real-time relationship change updates
paths:
  /v1/watch:
    post:
      operationId: WatchService_Watch
      summary: 'Watch returns a stream of events that occurred in the datastore in ascending timestamp order.

        The events can be relationship updates, schema updates, or checkpoints.'
      tags:
      - Watch
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WatchRequest'
      responses:
        '200':
          description: A successful response.(streaming responses)
          content:
            application/json:
              schema:
                type: object
                properties:
                  result:
                    $ref: '#/components/schemas/WatchResponse'
                  error:
                    $ref: '#/components/schemas/Status'
                title: Stream result of WatchResponse
        default:
          description: An unexpected error response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Status'
components:
  schemas:
    WatchResponse:
      type: object
      properties:
        updates:
          type: array
          items:
            type: object
            $ref: '#/components/schemas/RelationshipUpdate'
          description: 'updates are the RelationshipUpdate events that have occurred since the

            call was made, or since the point in time specified by changes_through.'
        changesThrough:
          $ref: '#/components/schemas/ZedToken'
          description: 'changes_through is the ZedToken that represents the point in time

            that the watch response is current through. This token can be used

            in a subsequent WatchRequest to resume watching from this point.'
        optionalTransactionMetadata:
          type: object
          description: 'optional_transaction_metadata is an optional field that returns the transaction metadata

            given to SpiceDB during the transaction that produced the changes in this response.

            This field may not exist if no transaction metadata was provided, or if multiple pieces

            of metadata were found during the transaction (in which case it is ambiguous which to return).'
        schemaUpdated:
          type: boolean
          description: schema_updated, if true, indicates that the schema was changed in this revision.
        isCheckpoint:
          type: boolean
          description: 'is_checkpoint, if true, indicates that a checkpoint was reached.

            A checkpoint indicates that the server guarantees that the client

            will not observe any changes at a revision below or equal to the revision in this response.'
        fullRevisionMetadata:
          type: array
          items:
            type: object
          description: 'full_revision_metadata contains all transaction metadata given to SpiceDB during the

            revision that produced the changes in this response. Some datastores (such as CockroachDB)

            can "merge" multiple transactions into a single revision (if the changes occurred concurrently),

            so this field is a list of all transaction metadata seen during the revision.'
      description: 'WatchResponse contains all mutation events in ascending timestamp order.

        This excludes relationships that were deleted because they expired.

        The response includes a field that can be used to resume

        watching from that point.'
    RelationFilter:
      type: object
      properties:
        relation:
          type: string
    Status:
      type: object
      properties:
        code:
          type: integer
          format: int32
          description: 'The status code, which should be an enum value of

            [google.rpc.Code][google.rpc.Code].'
        message:
          type: string
          description: 'A developer-facing error message, which should be in English. Any

            user-facing error message should be localized and sent in the

            [google.rpc.Status.details][google.rpc.Status.details] field, or localized

            by the client.'
        details:
          type: array
          items:
            type: object
            $ref: '#/components/schemas/Any'
          description: 'A list of messages that carry the error details.  There is a common set of

            message types for APIs to use.'
      description: 'The `Status` type defines a logical error model that is suitable for

        different programming environments, including REST APIs and RPC APIs. It is

        used by [gRPC](https://github.com/grpc). Each `Status` message contains

        three pieces of data: error code, error message, and error details.


        You can find out more about this error model and how to work with it in the

        [API Design Guide](https://cloud.google.com/apis/design/errors).'
    RelationshipUpdate:
      type: object
      properties:
        operation:
          $ref: '#/components/schemas/RelationshipUpdate.Operation'
        relationship:
          $ref: '#/components/schemas/Relationship'
      description: 'RelationshipUpdate is used for mutating a single relationship within the

        service.


        CREATE will create the relationship only if it doesn''t exist, and error

        otherwise.


        TOUCH will upsert the relationship, and will not error if it

        already exists.


        DELETE will delete the relationship. If the relationship does not exist,

        this operation will no-op.'
    SubjectFilter:
      type: object
      properties:
        subjectType:
          type: string
        optionalSubjectId:
          type: string
        optionalRelation:
          $ref: '#/components/schemas/RelationFilter'
      description: 'SubjectFilter specifies a filter on the subject of a relationship.


        subject_type is required and all other fields are optional, and will not

        impose any additional requirements if left unspecified.'
    SubjectReference:
      type: object
      properties:
        object:
          $ref: '#/components/schemas/ObjectReference'
        optionalRelation:
          type: string
      title: 'SubjectReference is used for referring to the subject portion of a

        Relationship. The relation component is optional and is used for defining a

        sub-relation on the subject, e.g. group:123#members'
    Any:
      type: object
      properties:
        '@type':
          type: string
          description: "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n  value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n  URL, or have them precompiled into a binary to avoid any\n  lookup. Therefore, binary compatibility needs to be preserved\n  on changes to types. (Use versioned type names to manage\n  breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics."
      additionalProperties: {}
      description: "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n    Foo foo = ...;\n    Any any;\n    any.PackFrom(foo);\n    ...\n    if (any.UnpackTo(&foo)) {\n      ...\n    }\n\nExample 2: Pack and unpack a message in Java.\n\n    Foo foo = ...;\n    Any any = Any.pack(foo);\n    ...\n    if (any.is(Foo.class)) {\n      foo = any.unpack(Foo.class);\n    }\n    // or ...\n    if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n      foo = any.unpack(Foo.getDefaultInstance());\n    }\n\n Example 3: Pack and unpack a message in Python.\n\n    foo = Foo(...)\n    any = Any()\n    any.Pack(foo)\n    ...\n    if any.Is(Foo.DESCRIPTOR):\n      any.Unpack(foo)\n      ...\n\n Example 4: Pack and unpack a message in Go\n\n     foo := &pb.Foo{...}\n     any, err := anypb.New(foo)\n     if err != nil {\n       ...\n     }\n     ...\n     foo := &pb.Foo{}\n     if err := any.UnmarshalTo(foo); err != nil {\n       ...\n     }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n    package google.profile;\n    message Person {\n      string first_name = 1;\n      string last_name = 2;\n    }\n\n    {\n      \"@type\": \"type.googleapis.com/google.profile.Person\",\n      \"firstName\": <string>,\n      \"lastName\": <string>\n    }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n    {\n      \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n      \"value\": \"1.212s\"\n    }"
    ObjectReference:
      type: object
      properties:
        objectType:
          type: string
        objectId:
          type: string
      description: ObjectReference is used to refer to a specific object in the system.
    ContextualizedCaveat:
      type: object
      properties:
        caveatName:
          type: string
          title: caveat_name is the name of the caveat expression to use, as defined in the schema
        context:
          type: object
          title: context consists of any named values that are defined at write time for the caveat expression
      description: 'ContextualizedCaveat represents a reference to a caveat to be used by caveated relationships.

        The context consists of key-value pairs that will be injected at evaluation time.

        The keys must match the arguments defined on the caveat in the schema.'
    RelationshipFilter:
      type: object
      properties:
        resourceType:
          type: string
          description: 'resource_type is the *optional* resource type of the relationship.

            NOTE: It is not prefixed with "optional_" for legacy compatibility.'
        optionalResourceId:
          type: string
          description: 'optional_resource_id is the *optional* resource ID of the relationship.

            If specified, optional_resource_id_prefix cannot be specified.'
        optionalResourceIdPrefix:
          type: string
          description: 'optional_resource_id_prefix is the *optional* prefix for the resource ID of the relationship.

            If specified, optional_resource_id cannot be specified.'
        optionalRelation:
          type: string
          description: relation is the *optional* relation of the relationship.
        optionalSubjectFilter:
          $ref: '#/components/schemas/SubjectFilter'
          description: optional_subject_filter is the optional filter for the subjects of the relationships.
      description: 'RelationshipFilter is a collection of filters which when applied to a

        relationship will return relationships that have exactly matching fields.


        All fields are optional and if left unspecified will not filter relationships,

        but at least one field must be specified.


        NOTE: The performance of the API will be affected by the selection of fields

        on which to filter. If a field is not indexed, the performance of the API

        can be significantly slower.'
    Relationship:
      type: object
      properties:
        resource:
          $ref: '#/components/schemas/ObjectReference'
          title: resource is the resource to which the subject is related, in some manner
        relation:
          type: string
          description: relation is how the resource and subject are related.
        subject:
          $ref: '#/components/schemas/SubjectReference'
          description: subject is the subject to which the resource is related, in some manner.
        optionalCaveat:
          $ref: '#/components/schemas/ContextualizedCaveat'
          title: optional_caveat is a reference to a the caveat that must be enforced over the relationship
        optionalExpiresAt:
          type: string
          format: date-time
          description: optional_expires_at is the time at which the relationship expires, if any.
      description: 'Relationship specifies how a resource relates to a subject. Relationships

        form the data for the graph over which all permissions questions are

        answered.'
    WatchKind:
      type: string
      enum:
      - WATCH_KIND_UNSPECIFIED
      - WATCH_KIND_INCLUDE_RELATIONSHIP_UPDATES
      - WATCH_KIND_INCLUDE_SCHEMA_UPDATES
      - WATCH_KIND_INCLUDE_CHECKPOINTS
      default: WATCH_KIND_UNSPECIFIED
      title: '- WATCH_KIND_UNSPECIFIED: Default, just relationship updates (for backwards compatibility)'
    WatchRequest:
      type: object
      properties:
        optionalObjectTypes:
          type: array
          items:
            type: string
          description: 'optional_object_types is a filter of resource object types to watch for relationship changes.

            If specified, only changes to the specified object types will be returned and

            optional_relationship_filters cannot be used.'
        optionalStartCursor:
          $ref: '#/components/schemas/ZedToken'
          description: 'optional_start_cursor is the ZedToken holding the point-in-time at

            which to start watching for changes.

            If not specified, the watch will start from the current SpiceDB revision time of the request ("head revision").

            Note that if this cursor references a point-in-time containing data

            that has been garbage collected, an error will be returned.'
        optionalRelationshipFilters:
          type: array
          items:
            type: object
            $ref: '#/components/schemas/RelationshipFilter'
          description: 'optional_relationship_filters, if specified, indicates the

            filter(s) to apply to each relationship to be returned by watch.

            The relationship will be returned as long as at least one filter matches,

            this allows clients to match relationships on multiple filters on a single watch call.

            If specified, optional_object_types cannot be used.'
        optionalUpdateKinds:
          type: array
          items:
            $ref: '#/components/schemas/WatchKind'
          description: 'optional_update_kinds, if specified, indicates what kinds of mutations to include.

            If your SpiceDB instance is running behind a proxy that aborts idle connections,

            we recommend including Checkpoints to keep the stream alive even when there are no changes.'
      description: 'WatchRequest specifies what mutations to watch for, and an optional start point for when to start

        watching.'
    RelationshipUpdate.Operation:
      type: string
      enum:
      - OPERATION_UNSPECIFIED
      - OPERATION_CREATE
      - OPERATION_TOUCH
      - OPERATION_DELETE
      default: OPERATION_UNSPECIFIED
    ZedToken:
      type: object
      properties:
        token:
          type: string
      description: 'ZedToken represents a point in time, or a "revision" in SpiceDB.

        It is used to provide causality metadata between Write and read requests (Check, ReadRelationships, LookupResources, LookupSubjects)

        and can also be used to start watching for changes from a specific point in time.


        See the authzed.api.v1.Consistency message for more information.'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: 'SpiceDB preshared-key. Pass as Authorization: Bearer <preshared-key>'