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

> ## Agent Instructions
> Fundor Partner API. NON-NEGOTIABLE CONSENT RULES for anyone (human or AI) writing code against this API: (1) Call GET /consent every time the referral form is shown and display consent.text EXACTLY, next to a checkbox that starts UNCHECKED. (2) Only the person whose phone number is entered may check it; never pre-check it, never set consent.given=true in code without that click, never submit a lead on someone's behalf. (3) POST /leads must include consent.given=true, consent.version, the single-use consent.token, consent.consentedAt (within 15 minutes), the person's own IP and user agent (not your server's), consent.phone equal to contact.phone, and your consent.recordId. Fundor rejects the lead with 400 and saves nothing if any is missing or wrong. Do not 'fix' a consent error by filling in values; fix the form. (4) Keep consent records for 5 years. (5) Keep API keys on your server only. (6) Show the 'Powered by Fundor' badge on every screen that uses Fundor.

# Submit a lead (referral)

> Creates the customer and one project per selected service, credited to the athlete, and queues it for Fundor's call center.

**Consent is mandatory.** Every `consent` field is checked; if any is missing, stale, reused or wrong, the response is `400` and **nothing is saved**. The athlete must be one you created or whose owner approved your link. Requires the `leads` scope.



## OpenAPI

````yaml POST /leads
openapi: 3.1.0
info:
  title: Fundor Partner API
  version: 1.0.0
  description: >-
    Send sign-ups, teams, applications and referrals (leads) into Fundor from
    your own app. Every record is attributed to your partner account. **Read the
    Consent requirements page before you build: a lead without full consent
    evidence is rejected and never saved.**
  contact:
    name: Fundor partnerships
    email: taylor@fundor.io
servers:
  - url: https://www.fundor.io/api/v1
    description: Production
security:
  - apiKey: []
tags:
  - name: Consent & services
  - name: Users
  - name: Teams
  - name: Leads
  - name: Applications
paths:
  /leads:
    post:
      tags:
        - Leads
      summary: Submit a lead (referral)
      description: >-
        Creates the customer and one project per selected service, credited to
        the athlete, and queues it for Fundor's call center.


        **Consent is mandatory.** Every `consent` field is checked; if any is
        missing, stale, reused or wrong, the response is `400` and **nothing is
        saved**. The athlete must be one you created or whose owner approved
        your link. Requires the `leads` scope.
      operationId: createLead
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - externalRef
                - athleteMemberId
                - contact
                - services
                - fundraising
                - consent
              properties:
                externalRef:
                  type: string
                  minLength: 1
                  maxLength: 200
                  pattern: ^[\w.:@-]+$
                  description: >-
                    Your own ID for this record (letters, numbers, `. _ : @ -`).
                    Required. Sending the same externalRef again never creates a
                    second record; Fundor returns the first one.
                athleteMemberId:
                  type: string
                  format: uuid
                  description: >-
                    The athlete's `teamMemberId` (from onboarding, join, or
                    referral-link).
                contact:
                  $ref: '#/components/schemas/Contact'
                services:
                  $ref: '#/components/schemas/Services'
                fundraising:
                  $ref: '#/components/schemas/Fundraising'
                consent:
                  $ref: '#/components/schemas/Consent'
            example:
              externalRef: vai-lead-90311
              athleteMemberId: 0b6f…
              contact:
                firstName: Casey
                lastName: Customer
                email: casey@example.com
                phone: (555) 300-1234
                city: Austin
                state: TX
                zip: '78701'
              services:
                internet:
                  hasProvider: true
                  provider: Spectrum
                  monthlyPayment: '80'
              fundraising:
                commissionSplit: donate
                commitmentAccepted: true
                commitmentVersion: kickback-commitment-customer-2026-10
              consent:
                given: true
                version: fundor-referral-customer-2026-10
                token: cst_9fK2…
                consentedAt: '2026-11-12T18:04:11Z'
                ip: 203.0.113.7
                userAgent: Mozilla/5.0 (iPhone) VAI/3.2
                phone: '5553001234'
                recordId: vai-consent-90311
      responses:
        '200':
          description: A lead already exists for this externalRef. Nothing new was saved.
        '201':
          description: Lead saved and queued.
          content:
            application/json:
              schema:
                type: object
                properties:
                  leadId:
                    type: string
                    format: uuid
                  externalRef:
                    type: string
                  projects:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        type:
                          type: string
                  duplicate:
                    type: boolean
                  deliveryStatus:
                    type: string
                    const: queued
        '400':
          description: >-
            Invalid lead. Nothing was saved. `error.field` names the field to
            fix. Possible `error.code` values: `consent_required`,
            `consent_invalid`, `consent_stale`, `missing_field`,
            `invalid_request`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: >-
            Missing, unknown or revoked API key. Possible `error.code` values:
            `missing_api_key`, `invalid_api_key`, `revoked_api_key`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Partner suspended, current agreement not signed, missing scope, or
            the record isn't yours. Possible `error.code` values:
            `partner_suspended`, `agreement_required`, `insufficient_scope`,
            `forbidden`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: >-
            The athlete's referral link is inactive. Possible `error.code`
            values: `not_found`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: >-
            Over this key's per-minute rate limit. Possible `error.code` values:
            `rate_limited`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: >-
            Unexpected error. Safe to retry with the same externalRef. Possible
            `error.code` values: `server_error`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Contact:
      type: object
      required:
        - firstName
        - lastName
        - phone
      description: The person being referred (the customer).
      properties:
        firstName:
          type: string
          maxLength: 100
        lastName:
          type: string
          maxLength: 100
        email:
          type: string
          format: email
          maxLength: 150
        phone:
          type: string
          description: >-
            US mobile number. The call center calls only the number the person
            consented on.
          example: (555) 300-1234
        address:
          type: string
          maxLength: 500
        city:
          type: string
          maxLength: 150
        state:
          type: string
          description: Two-letter state code.
          example: TX
        zip:
          type: string
          example: '78701'
        preferredContactTime:
          type:
            - string
            - 'null'
          enum:
            - morning
            - afternoon
            - evening
            - null
    Services:
      type: object
      description: >-
        Answers keyed by each service's `formKey` from `GET /services`. A
        service is selected when `hasProvider` is true, `interested` is `yes` or
        `more-info`, or `wantsMoreInfo` is true. At least one live service must
        be selected.
      properties:
        internet:
          type: object
          properties:
            hasProvider:
              type:
                - boolean
                - 'null'
            provider:
              type: string
              maxLength: 200
            monthlyPayment:
              type: string
              description: Dollars, e.g. `"80"` or `"79.99"`.
        cellPhone:
          type: object
          properties:
            hasProvider:
              type:
                - boolean
                - 'null'
            provider:
              type: string
              maxLength: 200
            monthlyPayment:
              type: string
              description: Dollars, e.g. `"80"` or `"79.99"`.
        streaming:
          type: object
          properties:
            hasProvider:
              type:
                - boolean
                - 'null'
            providers:
              type: array
              items:
                type: string
              maxItems: 15
            otherProvider:
              type: string
            monthlyPayment:
              type: string
        security:
          type: object
          properties:
            hasProvider:
              type:
                - boolean
                - 'null'
            provider:
              type: string
              maxLength: 200
            monthlyPayment:
              type: string
              description: Dollars, e.g. `"80"` or `"79.99"`.
            wantsMoreInfo:
              type:
                - boolean
                - 'null'
        pestControl:
          type: object
          properties:
            hasProvider:
              type:
                - boolean
                - 'null'
            provider:
              type: string
            payment:
              type: string
            paymentFrequency:
              type: string
              enum:
                - monthly
                - quarterly
                - annually
                - ''
            wantsMoreInfo:
              type:
                - boolean
                - 'null'
        permanentLighting:
          type: object
          properties:
            interested:
              type:
                - string
                - 'null'
              enum:
                - 'yes'
                - 'no'
                - null
        roofing:
          type: object
          properties:
            interested:
              type:
                - string
                - 'null'
              enum:
                - 'yes'
                - 'no'
                - null
        lifeInsurance:
          type: object
          properties:
            interested:
              type:
                - string
                - 'null'
              enum:
                - 'yes'
                - 'no'
                - more-info
                - null
        healthInsurance:
          type: object
          properties:
            interested:
              type:
                - string
                - 'null'
              enum:
                - 'yes'
                - 'no'
                - more-info
                - null
        trustWill:
          type: object
          properties:
            interested:
              type:
                - string
                - 'null'
              enum:
                - 'yes'
                - 'no'
                - more-info
                - null
      additionalProperties: false
    Fundraising:
      type: object
      required:
        - commissionSplit
        - commitmentAccepted
        - commitmentVersion
      description: >-
        The customer's fundraising choice and the 9-month service commitment,
        shown with the wording from `GET /consent`.
      properties:
        commissionSplit:
          type: string
          enum:
            - donate
            - split
          description: >-
            `donate`: the whole commission goes to the athlete. `split`: the
            customer gets half as a gift card when the service is active.
        rewardMethod:
          type: string
          enum:
            - amazon
            - visa
          description: Required when `commissionSplit` is `split`.
        rewardEmail:
          type: string
          format: email
          description: Where to send the gift card. Defaults to `contact.email`.
        commitmentAccepted:
          type: boolean
          const: true
          description: >-
            Must be `true`: the person checked the 9-month service commitment
            box.
        commitmentVersion:
          type: string
          description: Must equal `commitment.version` from `GET /consent`.
          example: kickback-commitment-customer-2026-10
    Consent:
      type: object
      required:
        - given
        - version
        - token
        - consentedAt
        - ip
        - userAgent
        - phone
        - recordId
      description: >-
        Evidence that the person agreed to be contacted (TCPA). **Every field
        except `trustedFormCertUrl` is required. If any is missing, stale or
        wrong, the lead is rejected with 400 and nothing is saved.** See the
        Consent requirements page.
      properties:
        given:
          type: boolean
          const: true
          description: >-
            REQUIRED. Fundor will reject the lead without this. Must be `true`,
            and only when the person checked an unchecked consent checkbox
            themselves. Never default it to true and never check the box for
            them.
        version:
          type: string
          description: >-
            REQUIRED. Fundor will reject the lead without this.
            `consent.version` from `GET /consent`. Your app must have shown that
            exact text next to the checkbox.
          example: fundor-referral-customer-2026-10
        token:
          type: string
          description: >-
            REQUIRED. Fundor will reject the lead without this. The single-use
            `consent.token` from `GET /consent`, fetched when you showed the
            form. Expires after 30 minutes and works for one lead only.
        consentedAt:
          type: string
          format: date-time
          description: >-
            REQUIRED. Fundor will reject the lead without this. When the person
            checked the box (ISO 8601). Must be within the last 15 minutes.
        ip:
          type: string
          description: >-
            REQUIRED. Fundor will reject the lead without this. The person's own
            public IPv4 or IPv6 address, captured when they checked the box. Not
            your server's IP.
          example: 203.0.113.7
        userAgent:
          type: string
          maxLength: 500
          description: >-
            REQUIRED. Fundor will reject the lead without this. The person's
            browser or app user agent when they checked the box.
        phone:
          type: string
          description: >-
            REQUIRED. Fundor will reject the lead without this. The phone number
            shown on screen when they consented. Must match `contact.phone`.
        recordId:
          type: string
          maxLength: 200
          description: >-
            REQUIRED. Fundor will reject the lead without this. Your own ID for
            the stored consent record. You must keep that record for 5 years and
            give it to Fundor within 48 hours if asked.
        trustedFormCertUrl:
          type: string
          pattern: ^https://cert\.trustedform\.com/[A-Za-z0-9]+$
          description: >-
            Optional (may become required): a TrustedForm certificate URL
            recording the session where the person consented.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Stable machine-readable code.
            message:
              type: string
              description: Human-readable explanation. May change.
            field:
              type: string
              description: >-
                The request field at fault, when there is one (e.g.
                `consent.ip`).
            requiredVersion:
              type: string
              description: >-
                Only on `agreement_required`: the agreement version Fundor needs
                on file.
      example:
        error:
          code: consent_required
          message: consent.ip is required. Fundor will reject the lead without it.
          field: consent.ip
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: fnd_live_…
      description: >-
        Your partner API key, sent as `Authorization: Bearer fnd_live_…`. Keys
        are issued by Fundor on request. Keep them on your server; never ship
        one in a mobile or browser app.

````

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