Skip to content

Webform inbound API

Pierre Lecointre edited this page Nov 7, 2025 · 2 revisions

Stood CRM Web Form API Documentation

For callout API refer to: https://github.com/Hway-Digital/stood-docs/wiki/Webhook-Callout-API

Version: 1.0
Last Updated: November 2025
Base URL: https://[REGION]-[PROJECT-ID].cloudfunctions.net


Table of Contents


Overview

The Stood CRM Web Form API allows you to programmatically submit contact, account, and deal information to your Stood CRM. This is ideal for:

  • Website contact forms
  • Lead capture pages
  • Third-party integrations
  • Marketing automation platforms
  • E-commerce order processing

Key Features:

  • ✅ Automatic deduplication of contacts and accounts
  • ✅ Support for custom fields
  • ✅ Flexible field mapping with dot notation
  • ✅ Built-in rate limiting and DDoS protection
  • ✅ Comprehensive validation
  • ✅ Automatic deal creation with source tracking

Authentication

All API requests require two authentication parameters:

Parameter Type Location Description
teamId string Body Your Stood CRM Team ID
teamKey string Body Your Web Form API Key (webFormKey)

How to Get Your Credentials

1. Team ID

  1. Log in to Stood CRM
  2. Go to AdminTeam Management
  3. Your Team ID is displayed in the team card header (e.g., zDdmpWNC5RcXSpTeklPw)
  4. Click the copy icon to copy it

2. Web Form API Key (teamKey)

  1. Log in to Stood CRM
  2. Go to AdminTeam Management
  3. Click on your team card
  4. Click on the Marketing Source section (orange box with campaign icon)
  5. Click "Generate" under WebForm API Key section
  6. Copy the generated key
  7. Click Save

⚠️ Security Warning: Keep your API Key secret! Anyone with this key can submit data to your CRM. Never expose it in client-side code or public repositories.


Base URL Structure

Your base URL follows this format:

https://[REGION]-[PROJECT-ID].cloudfunctions.net

Finding Your Base URL

  1. Go to Firebase Console
  2. Select your Stood CRM project
  3. Go to BuildFunctions
  4. Click on the webFormSubmit function
  5. Extract the region and project ID from the function URL

Example:

Function URL: https://webformsubmit-ccffslccvq-od.a.run.app
Project ID: stood-abcd
Region: europe-west9
Base URL: https://europe-west9-stood-abcd.cloudfunctions.net

Common Regions

Region Location
us-central1 Iowa, USA
us-east1 South Carolina, USA
europe-west1 Belgium
europe-west2 London, UK
europe-west9 Paris, France
asia-east1 Taiwan
asia-northeast1 Tokyo, Japan

Endpoints

Submit Web Form

Creates or updates contacts, accounts, and deals in Stood CRM.

Endpoint: POST /webFormSubmit

Full URL: https://[REGION]-[PROJECT-ID].cloudfunctions.net/webFormSubmit

Content-Type: application/json

Rate Limit:

  • 100 requests per minute per team

Request Format

Minimal Request

At minimum, you must provide either:

  • contact.email OR contact.phone
  • AND at least one of: contact.firstName, contact.lastName, OR account.name
{
  "teamId": "your-team-id",
  "teamKey": "your-api-key",
  "formData": {
    "contact.email": "john@example.com",
    "contact.firstName": "John",
    "contact.lastName": "Doe"
  }
}

Complete Request Example

{
  "teamId": "zDdmpWNC5RcXSpTeklPw",
  "teamKey": "sk_live_abc123def456xyz789",
  "formData": {
    "contact.firstName": "John",
    "contact.lastName": "Doe",
    "contact.email": "john.doe@acme.com",
    "contact.phone": "+1-555-123-4567",
    "contact.role": "CTO",
    "contact.location": "New York, NY",
    
    "account.name": "Acme Corporation",
    "account.location": "New York, NY",
    "account.website": "https://acme.com",
    "account.description": "Leading provider of roadrunner traps",
    
    "deal.name": "Acme Corp - Enterprise Plan",
    "deal.amount": 50000,
    "deal.stage": "s1",
    "deal.description": "Interested in our enterprise solution for Q1 2025",
    "deal.solution": "Enterprise Plan + Premium Support",
    "deal.closingDate": "2025-03-31",
    "deal.owner": "user-id-of-sales-rep",
    "deal.tags": ["enterprise", "high-priority"],
    
    "sourceName": "Website Contact Form"
  }
}

Custom Fields Example

{
  "teamId": "zDdmpWNC5RcXSpTeklPw",
  "teamKey": "sk_live_abc123def456xyz789",
  "formData": {
    "contact.email": "jane@startup.io",
    "contact.firstName": "Jane",
    "contact.lastName": "Smith",
    
    "account.name": "Startup Inc",
    
    "deal.name": "Startup Inc - Annual License",
    "deal.partnerKey": "PARTNER-2024-001",
    "deal.industry": "SaaS",
    "deal.referralSource": "LinkedIn Campaign",
    
    "account.companySize": "50-100",
    "account.annualRevenue": "5M-10M",
    
    "sourceName": "LinkedIn Ads Q4"
  }
}

Standard Fields

Fields that map directly to entity properties in Firestore.

Contact Standard Fields

Field Type Required Description
contact.firstName string Conditional* Contact's first name (max 500 chars)
contact.lastName string Conditional* Contact's last name (max 500 chars)
contact.email string Conditional** Valid email address
contact.phone string Conditional** Phone number (any format)
contact.role string No Job title or role
contact.location string No City, state, or full address

* At least one name field OR account.name is required
** Either email OR phone is required

Account Standard Fields

Field Type Required Description
account.name string Conditional* Account/company name (max 500 chars)
account.location string No Company location
account.website string No Company website URL
account.description string No Account description or notes (max 500 chars)
account.parent string No Parent account ID (for subsidiaries)

* Required if no contact.lastName provided

Deal Standard Fields

Field Type Required Description
deal.name string No Deal name (auto-generated if not provided)
deal.amount number No Deal value in team's currency (default: 0)
deal.stage string No Deal stage: s0, s1, s2, s3, s4 (default: s0)
deal.description string No Deal description or notes (max 500 chars)
deal.solution string No Proposed solution (max 500 chars)
deal.closingDate string No Expected close date (ISO 8601 or YYYY-MM-DD format)
deal.tags array No Array of tag strings
deal.owner string No User ID of the deal owner
deal.parent string No Parent deal ID (for sub-deals)

Deal Stages

Stage Label Description
s0 Lead/Prospect Initial contact (default)
s1 Qualified Qualified opportunity
s2 Proposal Proposal sent
s3 Won Deal closed successfully
s4 Lost Deal closed unsuccessfully

Special Field

Field Type Required Description
sourceName string No Marketing source/campaign name (used in deal naming and tracking)

Custom Fields

Any field not listed as a standard field is treated as a custom field and stored in the entity's customFields object.

Field Naming Convention

Use dot notation to specify the entity and field name:

entity.fieldName

Examples:

  • deal.partnerKey → Stored in deal's customFields as { partnerKey: "value" }
  • account.industry → Stored in account's customFields as { industry: "value" }
  • contact.linkedin → Stored in contact's customFields as { linkedin: "value" }

Custom Fields Example

{
  "teamId": "your-team-id",
  "teamKey": "your-api-key",
  "formData": {
    "contact.email": "user@company.com",
    "contact.firstName": "Alice",
    
    "deal.partnerKey": "PARTNER123",
    "deal.leadScore": "85",
    "deal.campaignId": "SUMMER2024",
    
    "account.industry": "Technology",
    "account.employeeCount": "500-1000",
    "account.annualRevenue": "50M-100M"
  }
}

Result in Firestore:

// Deal document
{
  name: "Company - ...",
  stage: "s0",
  customFields: {
    partnerKey: "PARTNER123",
    leadScore: "85",
    campaignId: "SUMMER2024"
  }
}

// Account document
{
  name: "Company",
  customFields: {
    industry: "Technology",
    employeeCount: "500-1000",
    annualRevenue: "50M-100M"
  }
}

Response Format

Success Response

HTTP Status: 200 OK

{
  "success": true,
  "accountId": "abc123def456",
  "contactId": "xyz789ghi012",
  "dealId": "jkl345mno678",
  "isNewContact": true,
  "isNewAccount": true
}
Field Type Description
success boolean Always true for successful requests
accountId string ID of created/updated account (may be empty)
contactId string ID of created/updated contact
dealId string ID of newly created deal
isNewContact boolean true if contact was created, false if updated
isNewAccount boolean true if account was created

Error Response

HTTP Status: 4xx or 5xx

{
  "success": false,
  "error": "Error message describing what went wrong"
}

Common Error Messages

HTTP Status Error Message Cause
403 Invalid team credentials Incorrect teamId or teamKey
400 Either contact.email or contact.phone is required Missing required contact identifier
400 At least contact.firstName, contact.lastName, or account.name is required Missing required name field
400 Invalid email format Email doesn't match validation regex
429 Too many submissions from this IP Rate limit exceeded (IP)
429 Too many submissions for this team Rate limit exceeded (team)
500 Internal server error Server-side error (check logs)

Rate Limiting

To prevent abuse and ensure fair usage, the API implements rate limiting:

Limit Type Threshold Window
Per IP Address 5 requests 1 minute
Per Team 100 requests 1 minute

Rate Limit Response

When rate limited, you'll receive:

HTTP Status: 429 Too Many Requests

{
  "success": false,
  "error": "Too many submissions from this IP. Please try again later."
}

Best Practices

  • Implement exponential backoff when retrying
  • Cache form submissions client-side to prevent duplicate submissions
  • Monitor your usage to stay within limits
  • Contact support if you need higher limits

Business Logic

Contact Deduplication

Contacts are matched by email or phone number within the same team:

  1. If a contact with the same email exists → Update contact data
  2. If a contact with the same phone exists → Update contact data
  3. Otherwise → Create new contact

Important: When updating an existing contact, their account link is preserved. The API will NOT change which account they belong to.

Account Handling

Accounts are matched by exact name:

  1. If account with exact name exists → Update account data
  2. Otherwise → Create new account

If no account.name is provided, a default account is created using contact.lastName.

Deal Creation

A new deal is ALWAYS created for each form submission:

  • Deal Name: Auto-generated as [Account/Contact Name] - [sourceName]
  • Account Link: Uses existing contact's account if contact was found, otherwise uses provided/created account
  • Contact Link: Added to relatedContacts array
  • Default Stage: s0 (Lead/Prospect)
  • Default Closing Date: 3 months from submission date
  • Source Tracking: sourceName is stored for campaign attribution

Contact Already Existed Behavior

When a contact already exists in the system:

  1. Contact data is updated (but account link preserved)
  2. A new deal is created
  3. Deal is linked to the contact's existing account
  4. A note is added to the deal description:
Note: Contact already existed in the system (matched by email or phone).

Code Examples

cURL

curl -X POST https://europe-west9-stood-abcd.cloudfunctions.net/webFormSubmit \
  -H "Content-Type: application/json" \
  -d '{
    "teamId": "zDdmpWNC5RcXSpTeklPw",
    "teamKey": "sk_live_abc123def456xyz789",
    "formData": {
      "contact.firstName": "John",
      "contact.lastName": "Doe",
      "contact.email": "john.doe@acme.com",
      "contact.phone": "+1-555-123-4567",
      "account.name": "Acme Corporation",
      "deal.description": "Interested in enterprise solution",
      "deal.amount": 50000,
      "sourceName": "Website Contact Form"
    }
  }'

JavaScript (Node.js)

const axios = require('axios');

async function submitToStoodCRM() {
  try {
    const response = await axios.post(
      'https://europe-west9-stood-abcd.cloudfunctions.net/webFormSubmit',
      {
        teamId: 'zDdmpWNC5RcXSpTeklPw',
        teamKey: 'sk_live_abc123def456xyz789',
        formData: {
          'contact.firstName': 'John',
          'contact.lastName': 'Doe',
          'contact.email': 'john.doe@acme.com',
          'contact.phone': '+1-555-123-4567',
          'account.name': 'Acme Corporation',
          'deal.description': 'Interested in enterprise solution',
          'deal.amount': 50000,
          'sourceName': 'Website Contact Form'
        }
      }
    );
    
    console.log('Success:', response.data);
    // {
    //   success: true,
    //   accountId: "...",
    //   contactId: "...",
    //   dealId: "...",
    //   isNewContact: true,
    //   isNewAccount: true
    // }
  } catch (error) {
    console.error('Error:', error.response.data);
  }
}

submitToStoodCRM();

JavaScript (Browser/Fetch API)

async function submitForm(formData) {
  try {
    const response = await fetch(
      'https://europe-west9-stood-abcd.cloudfunctions.net/webFormSubmit',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          teamId: 'zDdmpWNC5RcXSpTeklPw',
          teamKey: 'sk_live_abc123def456xyz789',
          formData: {
            'contact.firstName': formData.firstName,
            'contact.lastName': formData.lastName,
            'contact.email': formData.email,
            'contact.phone': formData.phone,
            'account.name': formData.company,
            'deal.description': formData.message,
            'sourceName': 'Contact Form'
          }
        })
      }
    );
    
    const result = await response.json();
    
    if (result.success) {
      console.log('✅ Submission successful!');
      console.log('Deal ID:', result.dealId);
    } else {
      console.error('❌ Submission failed:', result.error);
    }
  } catch (error) {
    console.error('❌ Network error:', error);
  }
}

Python

import requests
import json

def submit_to_stood_crm():
    url = "https://europe-west9-stood-abcd.cloudfunctions.net/webFormSubmit"
    
    payload = {
        "teamId": "zDdmpWNC5RcXSpTeklPw",
        "teamKey": "sk_live_abc123def456xyz789",
        "formData": {
            "contact.firstName": "John",
            "contact.lastName": "Doe",
            "contact.email": "john.doe@acme.com",
            "contact.phone": "+1-555-123-4567",
            "account.name": "Acme Corporation",
            "deal.description": "Interested in enterprise solution",
            "deal.amount": 50000,
            "sourceName": "Website Contact Form"
        }
    }
    
    headers = {
        "Content-Type": "application/json"
    }
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 200:
        result = response.json()
        print("✅ Success:", result)
        print(f"Deal ID: {result['dealId']}")
    else:
        print("❌ Error:", response.json())

submit_to_stood_crm()

PHP

<?php

function submitToStoodCRM() {
    $url = "https://europe-west9-stood-abcd.cloudfunctions.net/webFormSubmit";
    
    $data = array(
        "teamId" => "zDdmpWNC5RcXSpTeklPw",
        "teamKey" => "sk_live_abc123def456xyz789",
        "formData" => array(
            "contact.firstName" => "John",
            "contact.lastName" => "Doe",
            "contact.email" => "john.doe@acme.com",
            "contact.phone" => "+1-555-123-4567",
            "account.name" => "Acme Corporation",
            "deal.description" => "Interested in enterprise solution",
            "deal.amount" => 50000,
            "sourceName" => "Website Contact Form"
        )
    );
    
    $options = array(
        'http' => array(
            'header'  => "Content-Type: application/json\r\n",
            'method'  => 'POST',
            'content' => json_encode($data)
        )
    );
    
    $context  = stream_context_create($options);
    $result = file_get_contents($url, false, $context);
    
    if ($result === FALSE) {
        echo "❌ Error submitting form\n";
    } else {
        $response = json_decode($result, true);
        echo "✅ Success: " . print_r($response, true);
    }
}

submitToStoodCRM();
?>

Ruby

require 'net/http'
require 'json'
require 'uri'

def submit_to_stood_crm
  uri = URI('https://europe-west9-stood-abcd.cloudfunctions.net/webFormSubmit')
  
  payload = {
    teamId: 'zDdmpWNC5RcXSpTeklPw',
    teamKey: 'sk_live_abc123def456xyz789',
    formData: {
      'contact.firstName': 'John',
      'contact.lastName': 'Doe',
      'contact.email': 'john.doe@acme.com',
      'contact.phone': '+1-555-123-4567',
      'account.name': 'Acme Corporation',
      'deal.description': 'Interested in enterprise solution',
      'deal.amount': 50000,
      'sourceName': 'Website Contact Form'
    }
  }
  
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  
  request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/json'})
  request.body = payload.to_json
  
  response = http.request(request)
  result = JSON.parse(response.body)
  
  if result['success']
    puts "✅ Success: #{result}"
    puts "Deal ID: #{result['dealId']}"
  else
    puts "❌ Error: #{result['error']}"
  end
end

submit_to_stood_crm

Postman Collection

Import This Collection

{
  "info": {
    "name": "Stood CRM Web Form API",
    "description": "API for submitting contacts, accounts, and deals to Stood CRM",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://europe-west9-stood-abcd.cloudfunctions.net",
      "type": "string"
    },
    {
      "key": "teamId",
      "value": "your-team-id",
      "type": "string"
    },
    {
      "key": "teamKey",
      "value": "your-api-key",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Submit Web Form - Minimal",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"teamId\": \"{{teamId}}\",\n  \"teamKey\": \"{{teamKey}}\",\n  \"formData\": {\n    \"contact.email\": \"test@example.com\",\n    \"contact.firstName\": \"Test\",\n    \"contact.lastName\": \"User\"\n  }\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/webFormSubmit",
          "host": ["{{baseUrl}}"],
          "path": ["webFormSubmit"]
        },
        "description": "Minimal form submission with only required fields"
      }
    },
    {
      "name": "Submit Web Form - Complete",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"teamId\": \"{{teamId}}\",\n  \"teamKey\": \"{{teamKey}}\",\n  \"formData\": {\n    \"contact.firstName\": \"John\",\n    \"contact.lastName\": \"Doe\",\n    \"contact.email\": \"john.doe@acme.com\",\n    \"contact.phone\": \"+1-555-123-4567\",\n    \"contact.role\": \"CTO\",\n    \"contact.location\": \"New York, NY\",\n    \n    \"account.name\": \"Acme Corporation\",\n    \"account.location\": \"New York, NY\",\n    \"account.website\": \"https://acme.com\",\n    \"account.description\": \"Leading provider of roadrunner traps\",\n    \n    \"deal.name\": \"Acme Corp - Enterprise Plan\",\n    \"deal.amount\": 50000,\n    \"deal.stage\": \"s1\",\n    \"deal.description\": \"Interested in our enterprise solution for Q1 2025\",\n    \"deal.solution\": \"Enterprise Plan + Premium Support\",\n    \"deal.closingDate\": \"2025-03-31\",\n    \n    \"sourceName\": \"Website Contact Form\"\n  }\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/webFormSubmit",
          "host": ["{{baseUrl}}"],
          "path": ["webFormSubmit"]
        },
        "description": "Complete form submission with all available fields"
      }
    },
    {
      "name": "Submit Web Form - With Custom Fields",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"teamId\": \"{{teamId}}\",\n  \"teamKey\": \"{{teamKey}}\",\n  \"formData\": {\n    \"contact.email\": \"jane@startup.io\",\n    \"contact.firstName\": \"Jane\",\n    \"contact.lastName\": \"Smith\",\n    \n    \"account.name\": \"Startup Inc\",\n    \n    \"deal.name\": \"Startup Inc - Annual License\",\n    \"deal.amount\": 25000,\n    \"deal.partnerKey\": \"PARTNER-2024-001\",\n    \"deal.industry\": \"SaaS\",\n    \"deal.referralSource\": \"LinkedIn Campaign\",\n    \n    \"account.companySize\": \"50-100\",\n    \"account.annualRevenue\": \"5M-10M\",\n    \n    \"sourceName\": \"LinkedIn Ads Q4\"\n  }\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/webFormSubmit",
          "host": ["{{baseUrl}}"],
          "path": ["webFormSubmit"]
        },
        "description": "Form submission with custom fields"
      }
    },
    {
      "name": "Test Connection",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"teamId\": \"{{teamId}}\",\n  \"teamKey\": \"{{teamKey}}\",\n  \"formData\": {}\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/webFormSubmit",
          "host": ["{{baseUrl}}"],
          "path": ["webFormSubmit"]
        },
        "description": "Test connection with empty formData (validates credentials only)"
      }
    }
  ]
}

Setup Instructions

  1. Copy the JSON above
  2. Open Postman
  3. Click ImportRaw text
  4. Paste the JSON
  5. Click Import
  6. Set your variables:
    • baseUrl: Your Cloud Functions base URL
    • teamId: Your Team ID
    • teamKey: Your API Key

Best Practices

Security

  1. Never expose API keys client-side

    <!-- ❌ BAD: API key visible in browser -->
    <script>
      const teamKey = 'sk_live_abc123def456xyz789';
    </script>
  2. Use server-side proxy

    Browser → Your Server → Stood CRM API
    

    Your server holds the credentials and forwards sanitized data.

  3. Rotate keys regularly

    • Generate new API keys periodically
    • Revoke old keys after migration
  4. Monitor usage

    • Check Firestore logs for suspicious activity
    • Set up alerts for unusual patterns

Data Quality

  1. Validate before submitting

    // Validate email format
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      throw new Error('Invalid email');
    }
  2. Sanitize user input

    // Remove extra whitespace
    const cleanEmail = email.trim().toLowerCase();
  3. Use consistent formatting

    // Phone numbers: use international format
    const phone = '+1-555-123-4567'; // Good
    // Not: '555.123.4567' or '(555) 123-4567'

Performance

  1. Implement retry logic with exponential backoff

    async function submitWithRetry(data, maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        try {
          return await submit(data);
        } catch (error) {
          if (i === maxRetries - 1) throw error;
          await sleep(Math.pow(2, i) * 1000); // 1s, 2s, 4s
        }
      }
    }
  2. Debounce form submissions

    let submitTimeout;
    function debouncedSubmit(data) {
      clearTimeout(submitTimeout);
      submitTimeout = setTimeout(() => submit(data), 500);
    }
  3. Cache to prevent duplicates

    const submitted = new Set();
    function submitOnce(email, data) {
      if (submitted.has(email)) return;
      submit(data);
      submitted.add(email);
    }

Troubleshooting

Authentication Errors

Error: Invalid team credentials

Causes:

  • Incorrect Team ID (case-sensitive)
  • Incorrect API Key
  • API Key not yet generated

Solutions:

  1. Verify Team ID from Stood CRM Admin panel
  2. Regenerate API Key if lost
  3. Check for typos (trailing spaces, etc.)

Validation Errors

Error: Either contact.email or contact.phone is required

Solution: Include at least one contact identifier:

{
  "formData": {
    "contact.email": "user@example.com"
    // OR "contact.phone": "+1-555-1234"
  }
}

Error: At least contact.firstName, contact.lastName, or account.name is required

Solution: Provide at least one name field:

{
  "formData": {
    "contact.firstName": "John"
    // OR "contact.lastName": "Doe"
    // OR "account.name": "Acme Corp"
  }
}

Error: Invalid email format

Solution: Ensure email matches the pattern: name@domain.com

Rate Limiting

Error: Too many submissions from this IP

Solutions:

  1. Wait 1 minute before retrying
  2. Implement exponential backoff
  3. Contact support for higher limits

Network Errors

Error: Failed to fetch or Network error

Causes:

  • Incorrect base URL
  • CORS issues (browser-based requests)
  • Firewall blocking requests

Solutions:

  1. Verify base URL matches your Firebase region
  2. Use server-side proxy to avoid CORS
  3. Check firewall/network settings

Empty Response or 500 Error

Error: Internal server error

Causes:

  • Server-side error
  • Malformed request
  • Firestore permission issues

Solutions:

  1. Check Cloud Functions logs in Firebase Console
  2. Verify JSON is valid
  3. Ensure all required fields are strings (not objects/arrays unless specified)
  4. Contact support with error logs

Support

Resources

Getting Help

  1. Check Logs:

    • Firebase Console → Functions → Logs
    • Look for error details
  2. Community:

    • Check existing documentation
    • Review troubleshooting section
  3. Contact Support:

    • Email your Stood CRM administrator
    • Include:
      • Error messages
      • Request/response examples (remove sensitive data)
      • Timestamp of the issue
      • Your Team ID (not API key!)

Changelog

Version 1.0 (November 2025)

  • Initial API release
  • Support for contacts, accounts, and deals
  • Custom fields support
  • Rate limiting
  • Deduplication logic
  • Source tracking

Happy Integrating! 🚀

For the latest updates, visit the Stood CRM Documentation.

Clone this wiki locally