openapi: 3.1.0
info:
  title: Jupiter ERP Webhooks
  version: 1.0.0
  summary: Events Jupiter ERP POSTs to an HTTPS URL you register.
  description: >
    Jupiter ERP sends business events to your endpoint. You do not call these
    operations on Jupiter ERP.

    Each delivery is one HTTPS POST with a JSON body. The same event id can be
    delivered more than once.

    Amounts are integer cents. Manage endpoints in the Jupiter ERP panel under
    System → Webhooks.
servers: []
webhooks:
  webhook.ping:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PingEnvelope"
  invoice.created:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InvoiceCreatedEnvelope"
      summary: An invoice was created, including a draft.
  invoice.sent:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InvoiceSentEnvelope"
      summary: A finished invoice was sent.
  invoice.cancelled:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InvoiceCancelledEnvelope"
      summary: An invoice was cancelled. The credit note from that action is a
        separate credit_note.created event.
  credit_note.created:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreditNoteCreatedEnvelope"
      summary: A credit note was created, including one created by cancelling an
        invoice.
  credit_note.sent:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreditNoteSentEnvelope"
      summary: A credit note was sent.
  quote.created:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/QuoteCreatedEnvelope"
      summary: A quote was created.
  quote.accepted:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/QuoteAcceptedEnvelope"
      summary: A quote was accepted.
  quote.rejected:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/QuoteRejectedEnvelope"
      summary: A quote was rejected.
  contact.created:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactCreatedEnvelope"
      summary: A contact was created.
  contact.updated:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactUpdatedEnvelope"
      summary: A contact was saved. The item is the new snapshot, not a diff.
  receipt.created:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReceiptCreatedEnvelope"
      summary: A receipt was created. Later edits do not send another event.
  document.signed:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DocumentSignedEnvelope"
      summary: A recipient signed a document.
  document.declined:
    post:
      parameters:
        - $ref: "#/components/parameters/JupiterErpSignature"
        - $ref: "#/components/parameters/JupiterErpUserAgent"
      responses:
        "200":
          description: >
            Any 2xx status finishes the delivery. Respond within 10 seconds.

            410 turns the endpoint off. 429 and 5xx are retried.

            Other 4xx responses and redirects are not retried. Redirects are not
            followed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DocumentDeclinedEnvelope"
      summary: A recipient declined a signature. Expiry does not send an event.
components:
  parameters:
    JupiterErpSignature:
      name: Jupiter-ERP-Signature
      in: header
      required: true
      description: >
        `t` is a Unix timestamp. `v1` is hex HMAC-SHA256 of `{timestamp}.{raw
        body}` using the endpoint signing secret.
      schema:
        type: string
        examples:
          - t=1710000000,v1=0123456789abcdef
    JupiterErpUserAgent:
      name: User-Agent
      in: header
      required: true
      schema:
        type: string
        const: Jupiter-ERP-Webhook/1.0
  schemas:
    WebhookIdNameEmbed:
      type: object
      additionalProperties: false
      required:
        - id
        - name
      properties:
        id:
          type: integer
        name:
          type: string
    InvoiceWebhookItem:
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - number
        - formatted_number
        - date
        - sum_net
        - sum_gross
        - currency_code
      properties:
        id:
          type: integer
        status:
          type: string
          enum:
            - draft
            - open
            - partially_paid
            - paid
            - cancelled
        number:
          type: integer
        formatted_number:
          type: string
        date:
          type: string
          format: date
        sum_net:
          type: integer
          description: Net amount in cents.
        sum_gross:
          type: integer
          description: Gross amount in cents.
        currency_code:
          type: string
        contact:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        project:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        cost_center:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
    CreditNoteWebhookItem:
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - number
        - formatted_number
        - date
        - sum_net
        - sum_gross
        - currency_code
      properties:
        id:
          type: integer
        status:
          type: string
          enum:
            - draft
            - open
            - partially_paid
            - paid
        number:
          type: integer
        formatted_number:
          type: string
        date:
          type: string
          format: date
        sum_net:
          type: integer
          description: Net amount in cents.
        sum_gross:
          type: integer
          description: Gross amount in cents.
        currency_code:
          type: string
        contact:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        project:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        cost_center:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
    QuoteWebhookItem:
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - number
        - formatted_number
        - date
        - sum_net
        - sum_gross
        - currency_code
      properties:
        id:
          type: integer
        status:
          type: string
          enum:
            - draft
            - open
            - accepted
            - rejected
        number:
          type: integer
        formatted_number:
          type: string
        date:
          type: string
          format: date
        sum_net:
          type: integer
          description: Net amount in cents.
        sum_gross:
          type: integer
          description: Gross amount in cents.
        currency_code:
          type: string
        contact:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        project:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        cost_center:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
    ReceiptWebhookItem:
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - date
        - sum_net
        - sum_gross
        - currency_code
        - receipt_type
      properties:
        id:
          type: integer
        status:
          type: string
          enum:
            - draft
            - open
            - partially_paid
            - paid
            - cancelled
        date:
          type: string
          format: date
        sum_net:
          type: integer
          description: Net amount in cents.
        sum_gross:
          type: integer
          description: Gross amount in cents.
        currency_code:
          type: string
        receipt_type:
          type: string
          enum:
            - expense
            - income
        reference:
          type:
            - string
            - "null"
        issuer_reference:
          type:
            - string
            - "null"
        contact:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        project:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
        cost_center:
          oneOf:
            - $ref: "#/components/schemas/WebhookIdNameEmbed"
            - type: "null"
    ContactWebhookItem:
      type: object
      additionalProperties: false
      required:
        - id
        - type
        - is_organisation
        - name
      properties:
        id:
          type: integer
        type:
          type: string
          enum:
            - organisation
            - person
        is_organisation:
          type: boolean
        name:
          type: string
        company_name:
          type:
            - string
            - "null"
        contact_number:
          type:
            - integer
            - "null"
    DocumentSignatureWebhookItem:
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - document_type
        - document_id
      properties:
        id:
          type: integer
        status:
          type: string
          enum:
            - draft
            - pending
            - viewed
            - signed
            - declined
            - expired
            - cancelled
            - reset
        document_type:
          type: string
          description: Business document kind, for example invoice, quote, or credit_note.
        document_id:
          type: integer
    PingWebhookItem:
      type: object
      additionalProperties: false
      required:
        - ok
      properties:
        ok:
          type: boolean
          const: true
    PingEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: webhook.ping
            data:
              type: object
              additionalProperties: false
              required:
                - object
                - item
              properties:
                object:
                  const: ping
                item:
                  $ref: "#/components/schemas/PingWebhookItem"
    InvoiceCreatedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: invoice.created
            data:
              $ref: "#/components/schemas/InvoiceWebhookData"
    InvoiceSentEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: invoice.sent
            data:
              $ref: "#/components/schemas/InvoiceWebhookData"
    InvoiceCancelledEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: invoice.cancelled
            data:
              $ref: "#/components/schemas/InvoiceWebhookData"
    CreditNoteCreatedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: credit_note.created
            data:
              $ref: "#/components/schemas/CreditNoteWebhookData"
    CreditNoteSentEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: credit_note.sent
            data:
              $ref: "#/components/schemas/CreditNoteWebhookData"
    QuoteCreatedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: quote.created
            data:
              $ref: "#/components/schemas/QuoteWebhookData"
    QuoteAcceptedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: quote.accepted
            data:
              $ref: "#/components/schemas/QuoteWebhookData"
    QuoteRejectedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: quote.rejected
            data:
              $ref: "#/components/schemas/QuoteWebhookData"
    ContactCreatedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: contact.created
            data:
              $ref: "#/components/schemas/ContactWebhookData"
    ContactUpdatedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: contact.updated
            data:
              $ref: "#/components/schemas/ContactWebhookData"
    ReceiptCreatedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: receipt.created
            data:
              $ref: "#/components/schemas/ReceiptWebhookData"
    DocumentSignedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: document.signed
            data:
              $ref: "#/components/schemas/DocumentSignatureWebhookData"
    DocumentDeclinedEnvelope:
      allOf:
        - $ref: "#/components/schemas/WebhookEnvelopeBase"
        - type: object
          properties:
            type:
              const: document.declined
            data:
              $ref: "#/components/schemas/DocumentSignatureWebhookData"
    WebhookEnvelopeBase:
      type: object
      additionalProperties: false
      required:
        - id
        - type
        - api_version
        - created_at
        - account_uuid
        - data
      properties:
        id:
          type: string
          pattern: ^evt_
          description: Stable event id. The same id on a later POST is the same fact.
          examples:
            - evt_01J7ABCDEFGHJKMNPQRSTVWXYZ
        type:
          type: string
        api_version:
          type: string
          const: 1.0.0
        created_at:
          type: string
          format: date-time
          description: When the event was created. Retries keep this value.
        account_uuid:
          type: string
          format: uuid
          description: Send this value as X-Account-Uuid when you load the full record
            from the Account API.
    InvoiceWebhookData:
      type: object
      additionalProperties: false
      required:
        - object
        - item
      properties:
        object:
          const: invoice
        item:
          $ref: "#/components/schemas/InvoiceWebhookItem"
    CreditNoteWebhookData:
      type: object
      additionalProperties: false
      required:
        - object
        - item
      properties:
        object:
          const: credit_note
        item:
          $ref: "#/components/schemas/CreditNoteWebhookItem"
    QuoteWebhookData:
      type: object
      additionalProperties: false
      required:
        - object
        - item
      properties:
        object:
          const: quote
        item:
          $ref: "#/components/schemas/QuoteWebhookItem"
    ReceiptWebhookData:
      type: object
      additionalProperties: false
      required:
        - object
        - item
      properties:
        object:
          const: receipt
        item:
          $ref: "#/components/schemas/ReceiptWebhookItem"
    ContactWebhookData:
      type: object
      additionalProperties: false
      required:
        - object
        - item
      properties:
        object:
          const: contact
        item:
          $ref: "#/components/schemas/ContactWebhookItem"
    DocumentSignatureWebhookData:
      type: object
      additionalProperties: false
      required:
        - object
        - item
      properties:
        object:
          const: document_signature
        item:
          $ref: "#/components/schemas/DocumentSignatureWebhookItem"
