Skip to main content
The Signa API uses standard HTTP status codes and returns detailed error information in a consistent format.

Error Response Format

All errors follow this schema:
{
  "error": {
    "code": "invalid_request",
    "message": "The 'q' parameter is required for search requests",
    "details": {
      "parameter": "q",
      "reason": "missing_required_parameter"
    },
    "request_id": "req_abc123xyz",
    "documentation_url": "https://docs.signa.so/errors/invalid_request"
  }
}
Fields:
  • code — Machine-readable error code for programmatic handling
  • message — Human-readable error description
  • details — Additional context (optional)
  • request_id — Unique identifier for this request (include when contacting support)
  • documentation_url — Link to relevant documentation (optional)

HTTP Status Codes

Status CodeDescription
200Success — Request completed successfully
400Bad Request — Invalid request parameters
401Unauthorized — Invalid or missing API key
403Forbidden — Valid API key but insufficient permissions
404Not Found — Resource doesn’t exist
413Payload Too Large — Request body exceeds limit
429Too Many Requests — Credit quota exceeded
500Internal Server Error — Something went wrong on our end
503Service Unavailable — Temporary service disruption

Common Error Codes

Authentication Errors

unauthorized

Authentication failed due to missing or invalid API key.
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid API key provided",
    "request_id": "req_abc123xyz"
  }
}
Solutions:
  • Verify your API key is correct
  • Check that the Authorization header is properly formatted: Bearer YOUR_API_KEY
  • Ensure your API key hasn’t been revoked
  • Get a new key from the dashboard

api_key_expired

Your API key has expired.
{
  "error": {
    "code": "api_key_expired",
    "message": "API key expired on 2025-09-15. Please generate a new key.",
    "request_id": "req_abc123xyz"
  }
}
Solutions:
  • Generate a new API key in your dashboard
  • Update your application with the new key

Permission Errors

forbidden

Your API key is valid but doesn’t have permission for this operation.
{
  "error": {
    "code": "forbidden",
    "message": "This operation requires a paid plan",
    "details": {
      "required_plan": "Growth",
      "current_plan": "Starter",
      "feature": "semantic_search"
    },
    "request_id": "req_abc123xyz"
  }
}
Solutions:
  • Upgrade your plan to access this feature
  • Contact support if you believe this is an error

Request Errors

invalid_request

One or more request parameters are invalid.
{
  "error": {
    "code": "invalid_request",
    "message": "The 'q' parameter is required for search requests",
    "details": {
      "parameter": "q",
      "reason": "missing_required_parameter"
    },
    "request_id": "req_abc123xyz",
    "documentation_url": "https://docs.signa.so/api-overview#search"
  }
}
Common validation errors:
// Invalid parameter value
{
  "error": {
    "code": "invalid_request",
    "message": "Invalid office code 'USPO'. Valid codes: USPTO, EUIPO, UKIPO, WIPO",
    "details": {
      "parameter": "office",
      "invalid_value": "USPO",
      "valid_values": ["USPTO", "EUIPO", "UKIPO", "WIPO"]
    }
  }
}
// Invalid Nice class
{
  "error": {
    "code": "invalid_request",
    "message": "Invalid Nice class number. Must be between 1 and 45.",
    "details": {
      "parameter": "classes",
      "invalid_value": 50,
      "valid_range": [1, 45]
    }
  }
}
// Invalid search type
{
  "error": {
    "code": "invalid_request",
    "message": "Invalid search_type 'regex'. Valid types: exact, fuzzy, phonetic",
    "details": {
      "parameter": "search_type",
      "invalid_value": "regex",
      "valid_values": ["exact", "fuzzy", "phonetic"]
    }
  }
}
Solutions:
  • Check the error message for specific field issues
  • Verify parameters match the API specification
  • Ensure data types are correct (strings, numbers, arrays)
  • Review the documentation URL if provided

invalid_image

Image upload or URL is invalid.
{
  "error": {
    "code": "invalid_image",
    "message": "Unsupported image format. Supported: PNG, JPEG, GIF, WebP",
    "details": {
      "format_detected": "BMP",
      "supported_formats": ["PNG", "JPEG", "GIF", "WebP"]
    }
  }
}
Solutions:
  • Convert image to a supported format
  • Ensure image is not corrupted
  • Check image size is under 10MB

payload_too_large

Request body exceeds maximum size.
{
  "error": {
    "code": "payload_too_large",
    "message": "Bulk search limited to 100 queries per request",
    "details": {
      "queries_provided": 150,
      "max_queries": 100
    }
  }
}
Solutions:
  • Reduce the number of items in bulk requests
  • Split large requests into multiple smaller requests
  • For images, compress or resize before uploading

Resource Errors

not_found

The requested resource doesn’t exist.
{
  "error": {
    "code": "not_found",
    "message": "Trademark not found",
    "details": {
      "trademark_id": "tm_us_nonexistent"
    },
    "request_id": "req_abc123xyz"
  }
}
Solutions:
  • Verify the resource ID is correct
  • Check if the resource may have been deleted
  • Ensure you’re searching the correct office

monitor_not_found

Monitor with the specified ID doesn’t exist.
{
  "error": {
    "code": "monitor_not_found",
    "message": "Monitor mon_xyz not found",
    "request_id": "req_abc123xyz"
  }
}

Rate Limit Errors

quota_exceeded

You’ve exceeded your monthly credit quota.
{
  "error": {
    "code": "quota_exceeded",
    "message": "Monthly credit quota exceeded. Resets at 2025-11-01T00:00:00Z.",
    "details": {
      "credits_used": 10000,
      "credits_limit": 10000,
      "reset_at": "2025-11-01T00:00:00Z",
      "upgrade_url": "https://signa.so/pricing"
    },
    "request_id": "req_abc123xyz"
  }
}
Solutions:
  • Wait until the reset time indicated in the message
  • Upgrade your plan for more credits
  • Purchase overage credits
  • Implement exponential backoff in your retry logic
See Rate Limits Guide for details.

monitor_limit_exceeded

You’ve reached the maximum number of monitors for your plan.
{
  "error": {
    "code": "monitor_limit_exceeded",
    "message": "Monitor limit reached. Your plan allows 10 monitors.",
    "details": {
      "monitors_active": 10,
      "monitors_limit": 10,
      "upgrade_url": "https://signa.so/pricing"
    }
  }
}

Server Errors

internal_error

An unexpected error occurred on our servers.
{
  "error": {
    "code": "internal_error",
    "message": "An internal error occurred. Our team has been notified.",
    "request_id": "req_abc123xyz"
  }
}
Solutions:
  • Retry the request (we recommend exponential backoff)
  • If the problem persists, contact support with the request_id

service_unavailable

The API is temporarily unavailable.
{
  "error": {
    "code": "service_unavailable",
    "message": "Service temporarily unavailable. Please try again shortly.",
    "details": {
      "retry_after": 60
    },
    "request_id": "req_abc123xyz"
  }
}
Solutions:
  • Wait the specified retry_after seconds before retrying
  • Check status.signa.so for service status

Example Error Handling

async function searchTrademark(query) {
  try {
    const response = await fetch(
      `https://api.signa.so/v1/search?q=${encodeURIComponent(query)}`,
      {
        headers: {
          'Authorization': `Bearer ${process.env.TRADEMARK_API_KEY}`
        }
      }
    );

    if (!response.ok) {
      const error = await response.json();

      switch (error.error.code) {
        case 'quota_exceeded':
          console.error('Credit quota exceeded');
          console.log(`Resets at: ${error.error.details.reset_at}`);
          // Maybe implement a queue system
          break;

        case 'unauthorized':
          console.error('Invalid API key');
          // Check environment variables
          break;

        case 'invalid_request':
          console.error('Invalid request:', error.error.message);
          console.log('Details:', error.error.details);
          break;

        case 'internal_error':
          console.error('Server error. Request ID:', error.error.request_id);
          // Retry with exponential backoff
          break;

        default:
          console.error('API error:', error.error.message);
      }

      throw new Error(error.error.message);
    }

    return await response.json();
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}

Retry Logic with Exponential Backoff

For transient errors (500, 503), implement exponential backoff:
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      // Success
      if (response.ok) {
        return response;
      }

      const error = await response.json();

      // Don't retry client errors (4xx) except 429
      if (response.status >= 400 && response.status < 500 && response.status !== 429) {
        throw new Error(error.error.message);
      }

      // Retry server errors (5xx) and rate limits (429)
      if (attempt < maxRetries - 1) {
        const waitTime = Math.min(
          (2 ** attempt) * 1000, // Exponential: 1s, 2s, 4s...
          30000 // Max 30 seconds
        );

        console.log(`Retrying in ${waitTime}ms... (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
        continue;
      }

      // Max retries exceeded
      throw new Error(error.error.message);

    } catch (error) {
      if (attempt === maxRetries - 1) {
        throw error;
      }
    }
  }
}

Webhook Error Handling

When delivering webhooks, we expect:
  • 2xx response — Webhook accepted
  • Any other response — We’ll retry
We retry failed webhooks with exponential backoff:
  • Attempt 1: Immediately
  • Attempt 2: After 1 minute
  • Attempt 3: After 5 minutes
  • Attempt 4: After 30 minutes
  • Attempt 5: After 2 hours
After 5 failed attempts, the webhook is marked as failed and monitoring is paused. Handle errors gracefully:
app.post('/webhooks/trademarks', async (req, res) => {
  try {
    // Verify webhook signature (recommended)
    const signature = req.headers['x-trademark-signature'];
    if (!verifySignature(req.body, signature)) {
      return res.status(401).send('Invalid signature');
    }

    // Process webhook
    await processTrademarkEvent(req.body);

    // Always respond 2xx quickly
    res.status(200).send('OK');

  } catch (error) {
    console.error('Webhook processing failed:', error);

    // Still respond 2xx if you can handle async
    res.status(200).send('Accepted');

    // Process in background
    processInBackground(req.body);
  }
});
See Webhooks Guide for more details.

Getting Help

If you encounter persistent errors:
  1. Check the request_id in the error response
  2. Review your request parameters against the API documentation
  3. Test with a simple request to isolate the issue
  4. Check service status at status.signa.so
  5. Contact support at [email protected] with the request_id

Contact Support

Include the request_id from error responses for faster resolution

Error Code Reference

CodeHTTP StatusDescriptionRetryable
unauthorized401Invalid/missing API keyNo
api_key_expired401API key expiredNo
forbidden403Insufficient permissionsNo
invalid_request400Invalid parametersNo
invalid_image400Invalid image format/sizeNo
payload_too_large413Request too largeNo
not_found404Resource not foundNo
monitor_not_found404Monitor not foundNo
quota_exceeded429Credit limit exceededYes (after reset)
monitor_limit_exceeded429Too many monitorsNo
internal_error500Server errorYes
service_unavailable503Service downYes

Best Practices

Always log the request_id from errors for debugging and support:
console.error('API Error:', {
  code: error.error.code,
  message: error.error.message,
  request_id: error.error.request_id
});
Don’t just catch generic errors - handle specific error codes:
// Bad
catch (error) {
  console.log('Error occurred');
}

// Good
catch (error) {
  if (error.error?.code === 'quota_exceeded') {
    // Handle quota specifically
  } else if (error.error?.code === 'invalid_request') {
    // Handle validation specifically
  }
}
Only retry server errors (5xx) and rate limits (429). Retrying 4xx errors wastes time:
const shouldRetry = (status, errorCode) => {
  // Retry server errors
  if (status >= 500) return true;

  // Retry rate limits (but wait for reset)
  if (errorCode === 'quota_exceeded') return true;

  // Don't retry client errors
  return false;
};
Translate technical errors into user-friendly messages:
function getUserMessage(error) {
  switch (error.error.code) {
    case 'quota_exceeded':
      return 'Daily search limit reached. Try again tomorrow or upgrade your plan.';
    case 'invalid_request':
      return 'Please check your search term and try again.';
    case 'not_found':
      return 'Trademark not found. It may have been removed.';
    default:
      return 'Something went wrong. Please try again.';
  }
}