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

# Organisation Branding

> How to upload and retrieve your organisation's branding logo

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.

## Uploading Your Logo

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:
   * **UK**: [uk.veridox.ai](https://uk.veridox.ai)
   * **Canada**: [ca.veridox.ai](https://ca.veridox.ai)
2. Go to **Settings** → **Organisation** tab.
3. Scroll to the **Upload Branding Logo** section and upload your image.

**Supported formats**: PNG, JPG, JPEG, or SVG (recommended: PNG).

<Note>
  Uploading a new logo will overwrite any previously saved logo for your organisation.
</Note>

## Related API Endpoint

Once a logo has been uploaded via the dashboard, you can retrieve it programmatically:

* [`GET /organisation/branding`](../api-reference/endpoints/org-branding-get) - Get a signed download URL for the organisation logo

## Branding Workflow

```mermaid theme={null}
sequenceDiagram
    participant Admin as Org Admin
    participant Dashboard as Veridox Dashboard
    participant API as Veridox API
    participant Member as Org Member

    %% Upload Flow
    Admin->>Dashboard: Settings → Organisation → Upload Branding Logo
    Dashboard->>Admin: Logo uploaded successfully

    %% Retrieval Flow
    Member->>API: GET /organisation/branding
    API->>Member: Return signed download URL
    Member->>API: Access logo via download URL
```

## Step 1: Retrieve Organisation Logo

Any organisation member can retrieve the current organisation logo.

### Get Download URL

```bash theme={null}
curl -X GET "https://api.{region}.veridox.ai/organisation/branding" \
  -H "X-API-Key: vdx_your_api_key"
```

**Response (Logo exists):**

```json theme={null}
{
  "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):**

```json theme={null}
{
  "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

<Accordion title="Click to expand logo display implementation">
  ```javascript theme={null}
  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>
    );
  }
  ```
</Accordion>

## Error Handling

### API Key Errors

<Accordion title="Click to expand API key error handling example">
  ```javascript theme={null}
  // 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;
    }
  }
  ```
</Accordion>

## 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

* [`GET /organisation/branding`](../api-reference/endpoints/org-branding-get) - Get a signed download URL for the organisation logo
