> ## Documentation Index
> Fetch the complete documentation index at: https://docs.notifuse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Import custom events

> Imports multiple custom events in a single batch operation. Maximum 50 events per request. Auto-creates contacts if they don't exist.



## OpenAPI

````yaml /openapi.json post /api/customEvents.import
openapi: 3.0.3
info:
  title: Notifuse API
  description: API for Notifuse - a transactional email and newsletter management platform
  version: 1.0.0
  contact:
    name: Notifuse Support
    url: https://www.notifuse.com/support
    email: hello@notifuse.com
  license:
    name: BUSL-1.1
    url: https://github.com/Notifuse/notifuse/blob/main/LICENSE
servers:
  - url: https://{notifuseDomain}
    description: Customer-specific Notifuse API server
    variables:
      notifuseDomain:
        description: Your unique Notifuse domain
        default: demo.notifuse.com
security: []
paths:
  /api/customEvents.import:
    post:
      summary: Import custom events
      description: >-
        Imports multiple custom events in a single batch operation. Maximum 50
        events per request. Auto-creates contacts if they don't exist.
      operationId: importCustomEvents
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportCustomEventsRequest'
      responses:
        '201':
          description: Custom events imported successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportCustomEventsResponse'
        '400':
          description: Bad request - validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingWorkspaceId:
                  value:
                    error: workspace_id is required
                emptyEvents:
                  value:
                    error: events array cannot be empty
                tooManyEvents:
                  value:
                    error: maximum 50 events allowed per batch
                invalidEventName:
                  value:
                    error: >-
                      invalid event name: must contain only lowercase letters,
                      numbers, underscores, dots, and slashes
                missingRequiredFields:
                  value:
                    error: >-
                      event_name, external_id, and email are required for each
                      event
        '401':
          description: Unauthorized - invalid or missing authentication token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden - missing required permission
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error: contacts:write permission required
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error: Failed to create custom events
      security:
        - BearerAuth: []
components:
  schemas:
    ImportCustomEventsRequest:
      type: object
      required:
        - workspace_id
        - events
      properties:
        workspace_id:
          type: string
          description: The ID of the workspace
          example: ws_1234567890
        events:
          type: array
          description: Array of custom events to import (1-50 events)
          minItems: 1
          maxItems: 50
          items:
            type: object
            description: >-
              Each entry is an upsert on the (event_name, external_id) pair, not
              an append: an entry naming a resource that already exists updates
              it. Fields the entry leaves out keep the value already stored, so
              a partial entry is a safe way to correct one attribute. The
              exception is properties, which is replaced wholesale whenever the
              entry includes it.
            required:
              - event_name
              - external_id
              - email
            properties:
              event_name:
                type: string
                description: Event type name
                example: orders/fulfilled
                maxLength: 100
                pattern: ^[a-z0-9_./-]+$
              external_id:
                type: string
                description: External system identifier
                example: shopify_order_12345
                maxLength: 255
              email:
                type: string
                format: email
                description: Contact email address
                example: customer@example.com
              properties:
                type: object
                additionalProperties: true
                description: >-
                  The complete state of the resource. Omit the field to leave
                  the stored properties untouched; send an empty object to clear
                  them all. Including it replaces the stored set rather than
                  merging into it, so restate every property you want kept.
                example:
                  order_total: 129.99
                  product_name: Premium Subscription
              occurred_at:
                type: string
                format: date-time
                description: >-
                  When this version of the resource was produced. On an entry
                  naming an existing resource it is also the ordering guard:
                  unless deleted_at also changes, an entry whose occurred_at is
                  not strictly newer than the stored one is discarded in full
                  and still counted as imported. Defaults to the time of the
                  request.
                example: '2023-05-15T14:30:00Z'
              source:
                type: string
                enum:
                  - api
                  - integration
                  - import
                description: >-
                  Origin to record, defaulting to 'api' when the entry omits it.
                  It applies only where the entry creates the resource: an entry
                  naming one that already exists leaves the stored origin alone,
                  so re-importing cannot relabel a resource an integration
                  created.
                example: api
              integration_id:
                type: string
                description: >-
                  Integration reference. Preserved when the entry omits it, so
                  re-importing does not unlink a resource from the integration
                  that owns it.
                example: shopify_integration_123
              goal_type:
                type: string
                enum:
                  - purchase
                  - subscription
                  - lead
                  - signup
                  - booking
                  - trial
                  - other
                description: >-
                  Type of goal for conversion tracking. Kept when the entry
                  omits it; once set it can be changed but not cleared.
                example: purchase
              goal_name:
                type: string
                maxLength: 100
                description: >-
                  Optional goal name for categorization. Kept when the entry
                  omits it; once set it can be changed but not cleared.
                example: first_purchase
              goal_value:
                type: number
                format: double
                description: >-
                  Monetary value (required for purchase/subscription, can be
                  negative for refunds). Kept when the entry omits it; once set
                  it can be changed but not cleared.
                example: 99.99
              deleted_at:
                type: string
                format: date-time
                description: Soft delete timestamp
                example: null
          example:
            - event_name: orders/fulfilled
              external_id: shopify_order_12345
              email: customer@example.com
              properties:
                order_total: 129.99
                product_name: Premium Subscription
              occurred_at: '2023-05-15T14:30:00Z'
            - event_name: payment/succeeded
              external_id: stripe_payment_67890
              email: customer@example.com
              properties:
                amount: 129.99
                currency: USD
              occurred_at: '2023-05-15T14:29:00Z'
    ImportCustomEventsResponse:
      type: object
      properties:
        event_ids:
          type: array
          description: External IDs of successfully imported events
          items:
            type: string
          example:
            - shopify_order_12345
            - stripe_payment_67890
        count:
          type: integer
          description: Number of events created
          example: 2
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: Error message
      required:
        - error
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: API token for authentication

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.