Skip to main content
Organisation branding allows you to customise the visual appearance of your verification workflows with your own logo. The logo is applied at the organisation level and is visible to all members of your team. Logo upload is managed through the Veridox dashboard — it is not available via the API. Only organisation owners can upload or change the logo. To upload your logo:
  1. Sign in to your regional dashboard:
  2. Go to SettingsOrganisation tab.
  3. Scroll to the Upload Branding Logo section and upload your image.
Supported formats: PNG, JPG, JPEG, or SVG (recommended: PNG).
Uploading a new logo will overwrite any previously saved logo for your organisation.
Once a logo has been uploaded via the dashboard, you can retrieve it programmatically:

Branding Workflow

Any organisation member can retrieve the current organisation logo.

Get Download URL

curl -X GET "https://api.{region}.veridox.ai/organisation/branding" \
  -H "X-API-Key: vdx_your_api_key"
Response (Logo exists):
{
  "download_url": "https://storage.example.com/organisations/019be531-e891-71c5-b500-700cc780ecfd/branding/logo?sv=2025-11-05&se=2026-01-22T10%3A45%3A53Z&sr=b&sp=r&sig=oMF%2Ft%2Bit1CCAowIa2gCoW4ikmOVqUzQbOTYW2IzK1fE%3D",
  "expires_at": "2026-01-22T10:45:53.815Z"
}
Response (No logo uploaded):
{
  "error_code": "request.not-found",
  "error_message": "The resource '/organisations/branding-logo' does not exist.",
  "error_details": {
    "path": "/organisations/branding-logo"
  }
}

Display Logo in Application

class OrganisationBrandingDisplay {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.{region}.veridox.ai';
    this.logoUrl = null;
    this.expiresAt = null;
  }

  /**
   * Load organisation logo
   * @returns {Promise<string|null>} Logo URL or null if not found
   */
  async loadLogo() {
    try {
      const response = await fetch(`${this.baseUrl}/organisation/branding`, {
        headers: {
          'X-API-Key': this.apiKey
        }
      });

      if (response.status === 404) {
        console.log('No organisation logo uploaded');
        this.logoUrl = null;
        return null;
      }

      if (!response.ok) {
        const error = await response.json();
        throw new Error(`Failed to load logo: ${error.error_message}`);
      }

      const data = await response.json();
      this.logoUrl = data.download_url;
      this.expiresAt = new Date(data.expires_at);

      console.log('Logo loaded, expires at:', this.expiresAt);
      return this.logoUrl;

    } catch (error) {
      console.error('Failed to load organisation logo:', error);
      throw error;
    }
  }

  /**
   * Check if current logo URL is still valid
   * @returns {boolean} True if URL is still valid
   */
  isLogoUrlValid() {
    if (!this.expiresAt) return false;
    return new Date() < this.expiresAt;
  }

  /**
   * Get logo URL, refreshing if expired
   * @returns {Promise<string|null>} Valid logo URL
   */
  async getValidLogoUrl() {
    if (!this.logoUrl || !this.isLogoUrlValid()) {
      await this.loadLogo();
    }
    return this.logoUrl;
  }
}

// React Component Example
function OrganisationLogo({ apiKey, className = 'org-logo', fallbackText = 'Org' }) {
  const [logoUrl, setLogoUrl] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function loadLogo() {
      try {
        const branding = new OrganisationBrandingDisplay(apiKey);
        const url = await branding.loadLogo();
        setLogoUrl(url);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    loadLogo();
  }, [apiKey]);

  if (loading) return <div className="logo-loading">Loading...</div>;
  if (error) return <div className="logo-error">{fallbackText}</div>;

  return logoUrl ? (
    <img
      src={logoUrl}
      alt="Organisation Logo"
      className={className}
      onError={() => setLogoUrl(null)} // Fallback on load error
    />
  ) : (
    <div className={`${className} logo-fallback`}>
      {fallbackText}
    </div>
  );
}

Error Handling

API Key Errors

// Handle different API key error scenarios
async function handleBrandingRequest(apiKey) {
  try {
    const response = await fetch('/api/organisation/branding', {
      headers: { 'X-API-Key': apiKey }
    });

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

      switch (error.error_code) {
        case 'request.authentication.api-key.invalid':
          throw new Error('Invalid API key. Please check your key format.');
        case 'request.authentication.api-key.expired':
          throw new Error('API key has expired. Please generate a new key.');
        case 'request.authentication.api-key.membership-invalid':
          throw new Error('API key is no longer valid. Please contact your administrator.');
        case 'request.not-found':
          // No logo uploaded - this is expected
          return null;
        default:
          throw new Error(error.error_message || 'Unknown error occurred');
      }
    }

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

Best Practices

Retrieval Best Practices

  1. Cache URLs: Store download URLs briefly (respect 30-minute expiry)
  2. Lazy Loading: Load logos asynchronously to avoid blocking
  3. Fallbacks: Always have fallback branding when logo unavailable
  4. Refresh Logic: Check URL validity before using cached URLs
  5. Error Handling: Gracefully handle missing or expired logos

Security Considerations

  1. API Key Protection: Never expose API keys in client-side code
  2. Signed URLs: Respect URL expiration times
  3. HTTPS Only: Always use HTTPS for API communications
  4. CORS Awareness: Handle CORS properly for web applications
  5. Access Control: Understand admin vs member permission differences

Rate Limits

  • Download requests: 60 per hour per organisation
  • Download URL expiry: Signed download URLs expire after 30 minutes

Troubleshooting

Download Issues

  • 404 “resource does not exist”: No logo has been uploaded yet
  • “URL expired”: Request a fresh download URL
  • CORS errors: Ensure proper CORS configuration for your domain

Permission Issues

  • “Invalid API key”: Check API key format and validity
  • “Membership invalid”: User may have left the organisation

API Reference