openapi: 3.1.0
info:
  title: TradeEngage OpenAPI
  version: 1.0.0
  description: >
    The TradeEngage OpenAPI enables third-party systems to create and manage
    jobs

    within the TradeEngage referral network.


    ## Authentication


    All requests require an API key in the `X-TradeEngage-Signature` header.

    API keys are provisioned by TradeEngage administrators.


    ## Company Resolution


    The company context for each request is determined by:

    1. `service_titan_tenant_id` - Links to the company via ServiceTitan
    integration

    2. `brand_location_id` - The company's unique public identifier

    3. Default company - Falls back to the API key's configured default
  contact:
    name: TradeEngage API Support
    email: api-support@tradeengage.com
  license:
    name: Proprietary
    url: https://tradeengage.com/terms
servers:
  - url: https://api.tradeengage.com/api/v1/open
    description: Production
  - url: https://api.staging.tradeengage.com/api/v1/open
    description: Staging
security:
  - ApiKeyAuth: []
tags:
  - name: Jobs
    description: Job creation and management endpoints
paths:
  /jobs:
    post:
      operationId: createJob
      summary: Create a new job
      description: >
        Creates a new job in TradeEngage with the provided homeowner
        information.

        The job is automatically processed through the TradeEngage referral
        network

        to find qualified service providers.


        ## Idempotency


        This endpoint supports idempotent requests. If you provide an
        `idempotency_key`

        and a request with the same key has already been processed, the original

        response will be returned without creating a duplicate job.


        ## Job Context Requirements


        Every job requires context about what service the homeowner needs. This
        can be

        provided in one of two ways:


        1. **Summary**: A text description of the job (e.g., "Water heater
        replacement needed")

        2. **Call Transcript**: A transcript from a call center interaction


        At least one of these must be provided. If neither is available, the
        request

        will be rejected.


        ## Referring User vs Call Center Agent


        Jobs can be attributed to a referring user (the person who referred the
        job)

        or a call center agent (who took the call). If both are provided, the
        call

        center agent takes priority for attribution purposes.
      tags:
        - Jobs
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateJobRequest'
            examples:
              minimal:
                summary: Minimal request with summary
                description: >-
                  The simplest valid request with just homeowner info and a
                  summary
                value:
                  homeowner:
                    first_name: John
                    last_name: Doe
                    phone: '5551234567'
                    email: john.doe@example.com
                    zip_code: '90210'
                  summary: Customer needs HVAC repair - AC not cooling properly
              with_call_center:
                summary: Request with call center data
                description: Full request including call center agent and call transcript
                value:
                  homeowner:
                    first_name: Jane
                    last_name: Smith
                    phone: (555) 987-6543
                    email: jane.smith@example.com
                    zip_code: '33101'
                    street: 123 Main St
                    city: Miami
                    state: FL
                  call_center:
                    agent:
                      first_name: Mike
                      last_name: Agent
                      phone: '5555551234'
                      email: mike@callcenter.com
                    call:
                      transcript: >-
                        Customer called about a leaking water heater. Located in
                        garage. Approximately 10 years old. Needs replacement.
                  idempotency_key: 550e8400-e29b-41d4-a716-446655440000
                  source: CUSTOM_SOURCE
              with_service_titan:
                summary: Request with tenant id
                description: Request specifying the company via ServiceTitan integration
                value:
                  homeowner:
                    first_name: Bob
                    last_name: Wilson
                    phone: +1 555 123 4567
                    email: bob@example.com
                    zip_code: '75201'
                  summary: Plumbing issue - kitchen sink clogged
                  service_titan_tenant_id: st_tenant_12345
                  idempotency_key: 660e8400-e29b-41d4-a716-446655440001
                  external_identifiers:
                    service_titan_job_id: ST-JOB-789
                    crm_lead_id: LEAD-456
              with_referring_user:
                summary: Request with referring user
                description: Job referred by an employee or partner
                value:
                  homeowner:
                    first_name: Alice
                    last_name: Johnson
                    phone: '5559876543'
                    email: alice@example.com
                    zip_code: '60601'
                  referring_user:
                    first_name: Sarah
                    last_name: Referrer
                    phone: '5551112222'
                    email: sarah@hvaccompany.com
                  summary: Customer interested in new furnace installation
                  brand_location_id: hvac-company-chicago-001
      responses:
        '201':
          description: Job created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateJobResponse'
              example:
                data:
                  public_id: JOB-a1b2c3d4e5
                  status: HOMEOWNER_ACCEPTED
                  source: CUSTOM_SOURCE
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
              examples:
                missing_summary:
                  summary: Missing required context
                  value:
                    detail: Summary is required when call_center is not provided
                invalid_phone:
                  summary: Invalid phone number
                  value:
                    detail: Phone must be a valid US number
                invalid_zip:
                  summary: Invalid zip code
                  value:
                    detail: Zip code must be exactly 5 digits
        '401':
          description: Unauthorized - Invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missing_header:
                  summary: Missing authentication header
                  value:
                    detail: Missing X-TradeEngage-Signature header
                invalid_key:
                  summary: Invalid api key
                  value:
                    detail: Invalid API key
        '403':
          description: Forbidden - API key doesn't have access to the requested company
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                no_access:
                  summary: No company access
                  value:
                    detail: API key does not have access to the requested company
                no_default:
                  summary: No default company
                  value:
                    detail: >-
                      No company identifier provided and API key has no default
                      company. Provide either service_titan_tenant_id or
                      brand_location_id.
        '404':
          description: Company not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                tenant_not_found:
                  summary: Tenant not found
                  value:
                    detail: 'Company not found for tenant_id: st_tenant_invalid'
                brand_not_found:
                  summary: Brand location not found
                  value:
                    detail: 'Company not found for brand_location_id: invalid-location'
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-TradeEngage-Signature
      description: |
        API key for authentication. Keys are prefixed with `te_open_` and issued
        by TradeEngage administrators.

        Example: `te_open_abc123def456...`
  schemas:
    CreateJobRequest:
      type: object
      required:
        - homeowner
      properties:
        homeowner:
          $ref: '#/components/schemas/Homeowner'
        call_center:
          $ref: '#/components/schemas/CallCenter'
        referring_user:
          $ref: '#/components/schemas/ReferringUser'
        summary:
          type: string
          description: >
            A text description of the job or service needed. This is used to
            identify

            the job sector (HVAC, Plumbing, Electrical, etc.) and match with
            appropriate

            service providers.


            **Required** if `call_center.call.transcript` is not provided.
          example: Customer needs AC repair - unit not cooling, making strange noise
        service_titan_tenant_id:
          type: string
          description: |
            ServiceTitan tenant ID to identify the company creating this job.
            Used for companies integrated with ServiceTitan.

            Takes precedence over `brand_location_id` if both are provided.
          example: st_tenant_12345
        brand_location_id:
          type: string
          description: |
            Unique public identifier for the company/location creating this job.
            Used when `service_titan_tenant_id` is not available.
          example: hvac-company-dallas-001
        idempotency_key:
          type: string
          description: >
            Unique identifier for this request to enable idempotent operations.

            If a request with the same key has already been processed, the
            original

            response will be returned.


            Recommended format: UUID v4
          example: 550e8400-e29b-41d4-a716-446655440000
        external_identifiers:
          type: object
          additionalProperties:
            type: string
          description: |
            Key-value pairs for storing external system identifiers.
            Useful for correlating jobs with records in your own systems.
          example:
            service_titan_job_id: ST-12345
            crm_lead_id: LEAD-67890
            call_id: CALL-11111
        source:
          type: string
          description: |
            Identifier for the source system creating this job.
            Used for tracking and analytics.
          example: CUSTOM_SOURCE
      description: >
        ## Validation Rules


        1. **Homeowner is required** - Every job must have homeowner information


        2. **Job context is required** - At least one of the following must be
        provided:
           - `summary` - A text description of the job
           - `call_center.call.transcript` - A transcript from the call

        3. **Phone numbers** - Must be valid US phone numbers. Accepted formats:
           - `5551234567`
           - `555-123-4567`
           - `(555) 123-4567`
           - `+1 555 123 4567`

        4. **Zip codes** - Must be exactly 5 digits
    Homeowner:
      type: object
      required:
        - first_name
        - last_name
        - phone
        - zip_code
      properties:
        first_name:
          type: string
          description: Homeowner's first name
          example: John
        last_name:
          type: string
          description: Homeowner's last name
          example: Doe
        phone:
          type: string
          description: |
            Homeowner's phone number. Must be a valid US phone number.
            Will be normalized to international format (+1XXXXXXXXXX).
          example: '5551234567'
        email:
          type:
            - string
            - 'null'
          format: email
          description: Homeowner's email address (optional but recommended)
          example: john.doe@example.com
        zip_code:
          type: string
          pattern: ^\d{5}$
          description: 5-digit US zip code for the service location
          example: '90210'
        street:
          type:
            - string
            - 'null'
          description: Street address
          example: 123 Main Street
        city:
          type:
            - string
            - 'null'
          description: City name
          example: Beverly Hills
        state:
          type:
            - string
            - 'null'
          description: State abbreviation or full name
          example: CA
    CallCenter:
      type: object
      properties:
        agent:
          $ref: '#/components/schemas/Agent'
        call:
          $ref: '#/components/schemas/Call'
      description: |
        Call center information including the agent who handled the call
        and details about the call itself.

        If `agent` is provided, they will be credited as the referring user
        for this job (taking precedence over `referring_user`).
    Agent:
      type: object
      required:
        - first_name
        - last_name
        - phone
      properties:
        first_name:
          type: string
          description: Agent's first name
          example: Sarah
        last_name:
          type: string
          description: Agent's last name
          example: Smith
        email:
          type:
            - string
            - 'null'
          format: email
          description: Agent's email address
          example: sarah.smith@callcenter.com
        phone:
          type: string
          description: Agent's phone number (must be valid US number)
          example: '5559876543'
    Call:
      type: object
      required:
        - transcript
      properties:
        transcript:
          type: string
          description: |
            Full transcript of the call. Used to identify the job sector
            and understand the customer's needs.

            This can substitute for `summary` as the job context.
          example: >-
            Customer called about their AC unit not cooling. Unit is 15 years
            old, located in the attic. Making a loud noise when running.
    ReferringUser:
      type: object
      required:
        - first_name
        - last_name
        - phone
      properties:
        first_name:
          type: string
          description: Referring user's first name
          example: Mike
        last_name:
          type: string
          description: Referring user's last name
          example: Johnson
        email:
          type:
            - string
            - 'null'
          format: email
          description: Referring user's email address
          example: mike.johnson@company.com
        phone:
          type: string
          description: Referring user's phone number (must be valid US number)
          example: '5551112222'
      description: |
        The person who referred this job. This could be an employee, partner,
        or other contact who sourced the lead.

        **Note**: If `call_center.agent` is also provided, the agent takes
        precedence for attribution purposes.

        If the referring user doesn't exist in TradeEngage, they will be
        invited to create an account.
    CreateJobResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            public_id:
              type: string
              description: |
                Unique public identifier for the created job.
                Use this ID to query job status via the GET endpoint.
              example: JOB-a1b2c3d4e5
            status:
              type: string
              description: |
                Current status of the job. Newly created jobs typically
                have status `HOMEOWNER_ACCEPTED`.
              example: HOMEOWNER_ACCEPTED
            source:
              type:
                - string
                - 'null'
              description: The source identifier provided in the request
              example: CUSTOM_SOURCE
    Error:
      type: object
      properties:
        detail:
          type: string
          description: Human-readable error message
          example: Invalid API key
    ValidationError:
      type: object
      properties:
        detail:
          oneOf:
            - type: string
            - type: array
              items:
                type: object
                properties:
                  loc:
                    type: array
                    items:
                      oneOf:
                        - type: string
                        - type: integer
                    description: Location of the error in the request
                  msg:
                    type: string
                    description: Error message
                    example: field required
                  type:
                    type: string
                    description: Error type
                    example: missing
          description: Validation error details
