Funding Products
Merchant Cash Advance Business Line of Credit Working Capital Loans Business Term Loans SBA Loans Equipment Financing All 14 Funding Products →
Resources
MCA Calculator Factor Rate → APR Lender Directory Glossary (100+ terms) FAQs Partnerships
Company
Our Story Contact Us
Apply Now — Free (888) 896-5559
Developers · Partner API v1

Elite Funders Partner API

Submit deals and track status from your own software. One POST to submit. Webhooks when your deal moves.

Base URLhttps://mddbqtczelajfpsnviaz.supabase.co/functions/v1/partner-api-v1
Also available athttps://elitefunders.com/api/partner/v1
Authentication

One header, two key modes

Every request is authenticated with your partner API key in the Authorization header (or x-api-key). Live keys start with efp_live_ and create real deals; test keys start with efp_test_ and never write anything — see Sandbox. The only route that needs no key is GET /v1/openapi.json, which serves the machine-readable spec.

http
Authorization: Bearer efp_live_<your-key>
Quickstart

Ping, submit, track — three calls

1 Verify your key
curl
curl "https://mddbqtczelajfpsnviaz.supabase.co/functions/v1/partner-api-v1/v1/ping" \
  -H "Authorization: Bearer $EF_API_KEY"
2 Create a submission from deal.json

Include documents inline (base64) and set auto_submit: true to validate and submit in one call, or leave it off to create a draft you finish later. The Idempotency-Key header makes retries safe.

curl
curl -X POST "https://mddbqtczelajfpsnviaz.supabase.co/functions/v1/partner-api-v1/v1/submissions" \
  -H "Authorization: Bearer $EF_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: crm-10442-attempt-1" \
  --data @deal.json
deal.json
{
  "external_ref": "CRM-10442",
  "product_type": "mca",
  "business": {
    "legalName": "Blue Harbor Logistics LLC",
    "dba": "Blue Harbor",
    "entityType": "LLC",
    "industry": "Transportation",
    "inceptionDate": "03/2019",
    "phone": "3055550123",
    "monthlyRevenueEstimate": 85000,
    "ein": "123456789",
    "address": { "line1": "450 Port Blvd", "city": "Miami", "state": "FL", "zip": "33132" }
  },
  "owners": [{
    "firstName": "Jordan",
    "lastName": "Rivera",
    "email": "[email protected]",
    "phone": "3055550124",
    "ownershipPct": 100,
    "ssn": "123456789",
    "dob": "1984-06-02",
    "ficoMidpoint": 680,
    "address": { "line1": "88 Coral Way", "city": "Miami", "state": "FL", "zip": "33145" }
  }],
  "funding": { "requestedAmount": 75000, "useOfFunds": "Equipment and inventory", "openPositions": 0, "openBalance": 0 },
  "attestation": {
    "originalAppOnFile": true,
    "consentCredit": true,
    "consentTcpa": true,
    "consentEsign": true,
    "signatureName": "Jordan Rivera",
    "signedAt": "2026-09-15T14:30:00Z"
  },
  "documents": [
    { "kind": "statement", "ym": "2026-08", "filename": "aug-2026.pdf", "content_base64": "JVBERi0xLjc..." }
  ],
  "auto_submit": false
}
3 Attach remaining documents, then submit
curl
# attach more documents while the submission is a draft
curl -X POST "https://mddbqtczelajfpsnviaz.supabase.co/functions/v1/partner-api-v1/v1/submissions/$SUBMISSION_ID/documents" \
  -H "Authorization: Bearer $EF_API_KEY" -H "Content-Type: application/json" \
  --data '{"kind":"statement","ym":"2026-07","filename":"jul-2026.pdf","content_base64":"JVBERi0xLjc..."}'

# run the validation gates and submit the deal
curl -X POST "https://mddbqtczelajfpsnviaz.supabase.co/functions/v1/partner-api-v1/v1/submissions/$SUBMISSION_ID/submit" \
  -H "Authorization: Bearer $EF_API_KEY"

From here, poll GET /v1/submissions/{id} for status and timeline — or skip polling entirely and register a webhook. A 422 from /submit lists exactly what is missing; fix it and call /submit again.

Reference

Endpoints

All paths are relative to the base URL. Every route except GET /v1/openapi.json requires your API key.

EndpointWhat it does
GET/v1/pingVerify your key. Returns partner name, key mode, and your requests used this hour.
GET/v1/productsProducts, their document requirements, and — with ?state=FL — the exact bank-statement count required for that state.
POST/v1/submissionsCreate a deal submission. Honors Idempotency-Key; accepts inline documents and auto_submit.
GET/v1/submissionsList your submissions. Filters: status, created_after, external_ref, limit (max 100), offset.
GET/v1/submissions/{id}One submission: current status, documents, and a status timeline.
POST/v1/submissions/{id}/documentsAttach documents to a draft (single document or a documents array).
POST/v1/submissions/{id}/submitRun the full validation gates and submit the deal. 422 lists exactly what is missing.
POST/v1/webhooksRegister a webhook endpoint (HTTPS only, max 3 active). The signing secret is shown once, at creation.
GET/v1/webhooksList your webhook endpoints.
DELETE/v1/webhooks/{id}Disable a webhook endpoint.
POST/v1/webhooks/{id}/testSend a signed sample event to your endpoint.
GET/v1/openapi.jsonThe machine-readable OpenAPI 3.1 spec. No auth required.

Supported product_type values: mca (default), term_loan, loc, sba, equipment, heloc.

Reference

Documents

Documents are sent inline as base64 — up to 8 MB per file, 20 files per submission, and a 25 MB request body (split large batches across multiple /documents calls). Bank statements are required for all products; the count varies by state, so call GET /v1/products?state=XX for the exact requirement.

kindWhat it isAccepted filesExtra fields
statementA monthly bank statement..pdf .png .jpg .jpegym — the statement month as YYYY-MM (optional)
mtdMonth-to-date bank activity for the current month..pdf .png .jpg .jpeg
signed_applicationThe merchant-signed application on file with you..pdf only
extraAny additional product-specific document..pdf .png .jpg .jpeg .xls .xlsx .doc .docx .csvdoc_key — required; valid keys per product from GET /v1/products
Reference

Statuses

Once a deal is submitted, it moves through six partner-safe statuses. The API returns both a machine status code and a human status_label.

statusstatus_labelMeaning
receivedSubmittedDeal received by Elite Funders.
under_reviewIn reviewUnderwriting is reviewing the file.
approvedApprovedAn offer has been approved for the merchant.
contracts_outContracts outContracts have been sent for signature.
fundedFundedThe deal funded.
declinedDeclinedThe deal was declined.
Before submission, a submission you created without auto_submit has status draft. Test-mode submissions that pass validation get test_accepted instead of entering the pipeline — see Sandbox.
Reference

Webhooks

Register an HTTPS endpoint and we POST you a signed event whenever a deal moves. Events: submission.received, submission.under_review, submission.approved, submission.declined, submission.funded, and submission.offer_expiring. Failed deliveries are retried 5 times over ~14 hours; an endpoint is auto-disabled after 20 consecutive failures. Use POST /v1/webhooks/{id}/test to fire a signed sample event any time.

Event payload
POST https://yourapp.example/webhooks/elitefunders
X-Elite-Event: submission.approved
X-Elite-Signature: t=1789574400,v1=5f8a2c…

{
  "id": "7f0c5a4e-91d2-4c33-8f0a-2f6f6f1f2a9b",
  "event": "submission.approved",
  "mode": "live",
  "data": {
    "submission_id": "c1a2b3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "external_ref": "CRM-10442",
    "business_name": "Blue Harbor Logistics LLC",
    "status": "approved",
    "status_label": "Approved"
  },
  "created_at": "2026-09-16T18:00:00.000Z"
}

Verifying signatures

Every delivery carries X-Elite-Signature: t=<unix>,v1=<hex>, where v1 is HMAC-SHA256(secret, "<t>.<rawBody>") using the signing secret shown once when you registered the endpoint. Reject the delivery if the timestamp is more than 300 seconds off, or if the signature does not match. Always sign the raw request body — parse the JSON only after verification.

Node.js
const crypto = require("node:crypto");

function verifyEliteSignature(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((p) => p.split("="))
  );
  const t = Number(parts.t);
  if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  const given = String(parts.v1 || "");
  return (
    given.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(given))
  );
}

// Express example — keep the raw body for signing
app.post("/webhooks/elitefunders", express.raw({ type: "application/json" }), (req, res) => {
  if (!verifyEliteSignature(req.body.toString("utf8"), req.get("X-Elite-Signature") || "", process.env.ELITE_WEBHOOK_SECRET)) {
    return res.status(400).send("bad signature");
  }
  const event = JSON.parse(req.body);
  // handle event.event / event.data …
  res.sendStatus(200);
});
Python
import hmac, hashlib, time

def verify_elite_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in signature_header.split(","))
    try:
        t = int(parts["t"])
    except (KeyError, ValueError):
        return False
    if abs(time.time() - t) > 300:
        return False
    expected = hmac.new(
        secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

# Flask example — sign the raw body, parse JSON only after verifying
@app.route("/webhooks/elitefunders", methods=["POST"])
def elite_webhook():
    if not verify_elite_signature(
        request.get_data(),
        request.headers.get("X-Elite-Signature", ""),
        os.environ["ELITE_WEBHOOK_SECRET"],
    ):
        return "bad signature", 400
    event = request.get_json()
    # handle event["event"] / event["data"] …
    return "", 200
Reference

Errors & rate limits

Errors come back as a consistent JSON envelope with a machine-readable code and a request_id — include the request_id when contacting support. Every response also carries it in the X-Request-Id header.

Error shape
{
  "error": {
    "code": "validation_failed",
    "message": "Submission did not pass validation gates. Fix the listed items and call /submit again.",
    "details": { "errors": ["…"], "warnings": ["…"] }
  },
  "request_id": "a1b2c3d4-…"
}
HTTPcodeWhen
401missing_api_key / invalid_api_keyNo key, malformed key, or an unknown/revoked key.
403partner_inactiveYour partner account is not active.
404not_foundUnknown route, or a submission/webhook that isn't yours.
409duplicate_external_ref / not_a_draftAn external_ref you already used, or documents added after submit.
413payload_too_largeRequest body over 25 MB — split documents across multiple /documents calls.
422validation_failed, invalid_document, too_many_documents, …The response details list exactly what to fix.
429rate_limitedHourly limit exceeded. Honor the Retry-After header.
5xxinternal_error / engine_errorOur side. Retry later, or contact us with your request_id.

Rate limits are per key, per hour — one limit for requests overall and a separate one for submission creates, both sized to your account. GET /v1/ping reports your usage for the current hour. Use Idempotency-Key on POST /v1/submissions so a retried request returns the original submission instead of creating a duplicate.

Testing

Sandbox — test keys

Test keys (efp_test_) run the entire flow against the real validation gates but never create a real application or deal. Use one to integrate end-to-end before you switch to live:

  1. Create a submission and attach documents exactly as you would live.
  2. Call /submit — the full validation gates run. Failures return the same 422 with the same error list a live key would see.
  3. On success the submission gets status test_accepted and nothing enters the pipeline.
  4. Register a webhook and use POST /v1/webhooks/{id}/test to receive a signed sample event (delivered with "mode": "test") and prove out your signature verification.
  5. Swap in your efp_live_ key. No other code changes.

Getting access

The Partner API is available to approved ISO partners with a signed ISO agreement. API keys are issued manually by our partnerships team — email us with a note about your platform and we'll get you set up with a test key.