openapi: 3.0.3
info:
  title: Jelly API
  description: |
    The Jelly API allows you to manage labels, contacts, and conversations.

    We are still developing it, so there may be features missing. If you need something, please get in touch!

    All API requests require authentication using an API token in the Authorization header.
  version: 1.0.0
  contact:
    name: Jelly Support
    url: https://app.letsjelly.com

servers:
  - url: https://app.letsjelly.com/api
    description: Production server

security:
  - BearerAuth: []

tags:
  - name: Labels
    description: Labels help you and your team quickly identify and filter conversations. This API allows you to create labels automatically.
  - name: Conversation Labels
    description: Apply labels to conversations
  - name: Contacts
    description: Create and update contacts with links and labels

paths:
  /labels:
    get:
      tags:
        - Labels
      summary: List labels
      description: Get all labels for your team, ordered by name
      operationId: listLabels
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Label'
              example:
                - id: 1
                  name: Bug
                  color: cherry
                - id: 2
                  name: Feature
                  color: mint
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

    post:
      tags:
        - Labels
      summary: Create label
      description: Create a new label for your team
      operationId: createLabel
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - color
              properties:
                name:
                  type: string
                  description: Label name
                  example: Important
                color:
                  type: string
                  description: Label color
                  enum:
                    - gray
                    - gray-dark
                    - cherry
                    - cherry-dark
                    - apricot
                    - apricot-dark
                    - pineapple
                    - pineapple-dark
                    - gooseberry
                    - gooseberry-dark
                    - mint
                    - mint-dark
                    - juniper
                    - juniper-dark
                    - blueberry
                    - blueberry-dark
                    - huckleberry
                    - huckleberry-dark
                    - grape
                    - grape-dark
                    - plum
                    - plum-dark
                    - rhubarb
                    - rhubarb-dark
                    - strawberry
                    - strawberry-dark
                  example: cherry
      responses:
        '200':
          description: Label created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Label'
              example:
                id: 3
                name: Important
                color: cherry
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /conversations/{conversation_id}/labels:
    post:
      tags:
        - Conversation Labels
      summary: Add label to conversation
      description: Add a label to a specific conversation. There is not currently an API endpoint for listing conversations, but you can use our Webhook facility to be notified of new conversations and new messages automatically, and these will include the conversation ID required to use this API endpoint.
      operationId: addLabelToConversation
      parameters:
        - name: conversation_id
          in: path
          required: true
          description: ID of the conversation. This will often be in the form of a “slug”, e.g. `hows-the-weather-today-4bg2`
          schema:
            type: string
          example: my-bug
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - label_id
              properties:
                label_id:
                  type: integer
                  description: ID of the label to apply
                  example: 456
      responses:
        '201':
          description: Label applied successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Label'
                description: Array of all labels on the conversation
              example:
                - id: 3
                  name: Important
                  color: cherry
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /contacts:
    post:
      tags:
        - Contacts
      summary: Create or update contact
      description: Create a new contact or update an existing contact. The contact is identified by email address. This endpoint is primarily intended for use with an external CRM or tool. For example, you can use this to annotate contacts in Jelly with links to internal account tools, subscription pages and so on.
      operationId: createOrUpdateContact
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
                  description: Contact email address (case-insensitive)
                  example: john@example.com
                name:
                  type: string
                  description: Contact name
                  example: John Doe
                links:
                  type: array
                  description: Array of links associated with the contact
                  items:
                    type: object
                    properties:
                      title:
                        type: string
                        description: Link title
                      url:
                        type: string
                        format: uri
                        description: Link URL
                  example:
                    - title: LinkedIn
                      url: https://linkedin.com/in/johndoe
                    - title: Website
                      url: https://johndoe.com
      responses:
        '200':
          description: Contact updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact'
        '201':
          description: Contact created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              examples:
                emailRequired:
                  value:
                    error: Email is required
                validationError:
                  value:
                    error: Validation failed
        '500':
          $ref: '#/components/responses/InternalServerError'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: |
        API token authentication. Include your token in the Authorization header:

        `Authorization: Bearer YOUR_API_TOKEN`

        To get an API token:
        1. Go to your team settings in Jelly
        2. Navigate to "API Tokens"
        3. Create a new token and save it securely

  schemas:
    Label:
      type: object
      properties:
        id:
          type: integer
          description: Unique identifier for the label
          example: 1
        name:
          type: string
          description: Label name
          example: Bug
        color:
          type: string
          description: Label color
          enum:
            - gray
            - gray-dark
            - cherry
            - cherry-dark
            - apricot
            - apricot-dark
            - pineapple
            - pineapple-dark
            - gooseberry
            - gooseberry-dark
            - mint
            - mint-dark
            - juniper
            - juniper-dark
            - blueberry
            - blueberry-dark
            - huckleberry
            - huckleberry-dark
            - grape
            - grape-dark
            - plum
            - plum-dark
            - rhubarb
            - rhubarb-dark
            - strawberry
            - strawberry-dark
          example: cherry
      required:
        - id
        - name
        - color

    Contact:
      type: object
      properties:
        id:
          type: integer
          description: Unique identifier for the contact
          example: 42
        email:
          type: string
          format: email
          description: Contact email address
          example: john@example.com
        name:
          type: string
          nullable: true
          description: Contact name
          example: John Doe
        links:
          type: array
          description: Links associated with the contact
          items:
            type: object
            properties:
              title:
                type: string
                description: Link title
              url:
                type: string
                format: uri
                description: Link URL
          example:
            - title: LinkedIn
              url: https://linkedin.com/in/johndoe
      required:
        - id
        - email
        - links

    WebhookPayload:
      type: object
      description: Webhook payload sent when a new message arrives
      properties:
        url:
          type: string
          format: uri
          description: URL to the message in Jelly
        subject:
          type: string
          description: Message subject
        sent_at:
          type: string
          format: date-time
          description: When the message was sent
        from:
          type: array
          items:
            type: string
          description: Sender email addresses
        to:
          type: array
          items:
            type: string
          description: Recipient email addresses
        cc:
          type: array
          items:
            type: string
          description: CC email addresses
        bcc:
          type: array
          items:
            type: string
          description: BCC email addresses
        html_body:
          type: string
          description: HTML body of the message
        text_body:
          type: string
          description: Plain text body of the message
        attachments_count:
          type: integer
          description: Number of attachments
        conversation:
          type: object
          description: Conversation metadata
          properties:
            id:
              type: string
              description: Conversation ID
            url:
              type: string
              format: uri
              description: URL to the conversation in Jelly
            subject:
              type: string
              description: Conversation subject
            custom_subject:
              type: string
              nullable: true
              description: Custom subject if set
            messages_count:
              type: integer
              description: Total number of messages in the conversation
            got_by:
              type: string
              description: JSON string of users assigned to the conversation

    Error:
      type: object
      properties:
        error:
          type: string
          description: Error message
          example: Invalid API token

    ValidationErrors:
      type: object
      properties:
        errors:
          type: array
          items:
            type: string
          description: Array of validation error messages
          example:
            - Name can't be blank
            - Color is not included in the list

  responses:
    Unauthorized:
      description: Missing or invalid API token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            missingHeader:
              value:
                error: Missing or invalid Authorization header
            invalidToken:
              value:
                error: Invalid API token

    NotFound:
      description: Resource or endpoint not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            resourceNotFound:
              value:
                error: Resource not found
            endpointNotFound:
              value:
                error: Endpoint not found

    ValidationError:
      description: Validation errors
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationErrors'
          example:
            errors:
              - Name can't be blank
              - Color is not included in the list

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Internal server error
