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

# System Integrations

> Configuring a system integration in the backoffice

export const Callout = ({highlightKey, children}) => null;

export const AnnotatedShot = ({id, children}) => {
  const screenshots = {
    "domain-mappings.sync-trigger-actions-employee": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-actions-employee.png",
      caption: "Each sync trigger exposes action buttons for an ad-hoc sync and for editing the trigger configuration.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "sync-now",
        description: "Fires an immediate one-off sync without waiting for the next scheduled run. Handy when you want to see the effect of a configuration change right away.",
        x: 0.8854,
        y: 0.5056,
        w: 0.025,
        h: 0.0511
      }, {
        key: "edit",
        description: "Opens the edit modal where the schedule, parent trigger, scheduled toggles, and any domain-specific settings for this trigger can be adjusted.",
        x: 0.916,
        y: 0.5056,
        w: 0.025,
        h: 0.04
      }]
    },
    "domain-mappings.sync-trigger-edit-employee": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-edit-employee.png",
      caption: "The Edit Sync Trigger modal for a non-time-report mapping.",
      w: 900,
      h: 1124,
      highlights: [{
        key: "cron-enabled",
        description: "Controls whether the trigger fires automatically. When it is turned off, the trigger only runs if someone starts it manually.",
        x: 0.0556,
        y: 0.3149,
        w: 0.2336,
        h: 0.0783
      }, {
        key: "cron-expression",
        description: "Standard cron syntax that determines when the trigger runs while the schedule is enabled.",
        x: 0.3247,
        y: 0.3149,
        w: 0.6198,
        h: 0.1103
      }, {
        key: "scheduled-toggles",
        description: "Queues future flips of the enable state. Useful for pausing a trigger during a maintenance window and having it re-enable itself afterwards without manual intervention.",
        x: 0.0556,
        y: 0.468,
        w: 0.8889,
        h: 0.2349
      }, {
        key: "parent-trigger",
        description: "Chains this trigger to run immediately after another one completes, so dependent syncs always happen in the right order.",
        x: 0.0556,
        y: 0.7456,
        w: 0.8889,
        h: 0.1032
      }]
    },
    "domain-mappings.sync-trigger-actions-time-report": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-actions-time-report.png",
      caption: "Time-report mappings expose the same sync trigger actions as other domains.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "sync-now",
        description: "Fires an immediate sync. On time-report mappings this first opens a small dialog for picking the date range to pull before the sync actually runs.",
        x: 0.8854,
        y: 0.5056,
        w: 0.025,
        h: 0.0511
      }, {
        key: "edit",
        description: "Opens the edit modal. For a time-report mapping this exposes an extra section for the default date range the scheduled sync should cover.",
        x: 0.916,
        y: 0.5056,
        w: 0.025,
        h: 0.04
      }]
    },
    "domain-mappings.sync-trigger-edit-time-report": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-edit-time-report.png",
      caption: "The Edit Sync Trigger modal for a time-report mapping exposes an extra date-range section.",
      w: 900,
      h: 1388,
      highlights: [{
        key: "cron-enabled",
        description: "Controls whether the trigger fires automatically. When it is turned off, the trigger only runs if someone starts it manually.",
        x: 0.0556,
        y: 0.255,
        w: 0.2336,
        h: 0.0634
      }, {
        key: "cron-expression",
        description: "Standard cron syntax that determines when the trigger runs while the schedule is enabled.",
        x: 0.3247,
        y: 0.255,
        w: 0.6198,
        h: 0.0893
      }, {
        key: "scheduled-toggles",
        description: "Queues future flips of the enable state. Useful for pausing a trigger during a maintenance window and having it re-enable itself afterwards without manual intervention.",
        x: 0.0556,
        y: 0.379,
        w: 0.8889,
        h: 0.1902
      }, {
        key: "parent-trigger",
        description: "Chains this trigger to run immediately after another one completes, so dependent syncs always happen in the right order.",
        x: 0.0556,
        y: 0.6037,
        w: 0.8889,
        h: 0.0836
      }, {
        key: "time-report-settings",
        description: "Defines which date range the sync should pull time reports for. The start and end dates can each be either a fixed date or a dynamic expression evaluated at run time.",
        x: 0.0556,
        y: 0.7219,
        w: 0.8889,
        h: 0.1556
      }]
    },
    "domain-mappings.employee-outgoing": {
      path: "images/backoffice/configuration/domain-mappings/employee-outgoing.png",
      caption: "An outgoing Employee → Employee mapping pushes Twine employee data into a target system.",
      w: 2880,
      h: 1800
    },
    "domain-mappings.time-report": {
      path: "images/backoffice/configuration/domain-mappings/time-report.png",
      caption: "Time report mappings include a dedicated time-code mapping section alongside the standard configuration.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "time-code-mapping",
        description: "Appears only on time report to time report mappings. Lines up each time code in the source system with the matching Twine time code so reported hours land in the right bucket downstream.",
        x: 0.1778,
        y: 0.4256,
        w: 0.4,
        h: 0.5567
      }]
    },
    "jobs.details": {
      path: "images/backoffice/daily-operations/jobs/details.png",
      caption: "The Job Details page shows everything about a single sync job — its metadata, status, descendants, and streaming logs.",
      w: 2880,
      h: 1800
    },
    "system-integration-settings.authentication": {
      path: "images/backoffice/configuration/system-integration-settings/authentication.png",
      caption: "The Authentication sub-tab holds credentials and a sharable authentication URL generator.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "generate-url-button",
        description: "Generates a one-time shareable URL that lets a customer without a Twine login enter their own credentials. The link stays valid for five days.",
        x: 0.816,
        y: 0.3378,
        w: 0.1555,
        h: 0.04
      }]
    },
    "system-integration-settings.authentication-url-generated": {
      path: "images/backoffice/configuration/system-integration-settings/authentication-url-generated.png",
      caption: "After clicking Generate Authentication URL, the card displays the shareable link with a copy button.",
      w: 872,
      h: 948,
      highlights: [{
        key: "copy-button",
        description: "Copies the generated link to the clipboard so it can be pasted into an email or chat to the customer.",
        x: 0.8945,
        y: 0.692,
        w: 0.0275,
        h: 0.0253
      }]
    },
    "system-integration-settings.general": {
      path: "images/backoffice/configuration/system-integration-settings/general.png",
      caption: "The General sub-tab holds system-specific settings that are not credentials.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "system-specific-card",
        description: "Holds configuration that is specific to the connected system and unrelated to authentication. The exact fields depend on which integration is selected.",
        x: 0.6861,
        y: 0.2633,
        w: 0.3028,
        h: 0.28
      }]
    },
    "system-integration-settings.time-reports": {
      path: "images/backoffice/configuration/system-integration-settings/time-reports.png",
      caption: "The Time Reports & Types sub-tab configures how source time codes map to Twine time codes.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "refresh-button",
        description: "Re-fetches the current time-type catalogue from the connected system so the mapping list picks up anything that has been added or removed upstream.",
        x: 0.3896,
        y: 0.9144,
        w: 0.1529,
        h: 0.04
      }]
    },
    "system-integrations.admin": {
      path: "images/backoffice/configuration/system-integrations/admin.png",
      caption: "The Admin tab exposes destructive and one-shot administrative actions for a system integration.",
      w: 2880,
      h: 1800
    },
    "system-integrations.domains-overview": {
      path: "images/backoffice/configuration/system-integrations/domains-overview.png",
      caption: "The Domains tab lists outgoing and incoming domain mappings for this system integration.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "create-button",
        description: "Opens a dialog where you pick the direction, target integration, and source and target domains for a new mapping.",
        x: 0.8297,
        y: 0.2633,
        w: 0.1592,
        h: 0.04
      }]
    },
    "system-integrations.domains-create-dialog": {
      path: "images/backoffice/configuration/system-integrations/domains-create-dialog.png",
      caption: "The Create Domain Mapping dialog starts with the direction radio and an empty form.",
      w: 900,
      h: 964
    },
    "system-integrations.domains-create-dialog-filled": {
      path: "images/backoffice/configuration/system-integrations/domains-create-dialog-filled.png",
      caption: "Once a target system integration and source/target domains are selected, the Create button unlocks.",
      w: 900,
      h: 964
    },
    "anomalies.list": {
      path: "images/backoffice/daily-operations/anomalies/list.png",
      caption: "The Anomalies page lists issues grouped by severity, system, and status.",
      w: 2880,
      h: 1800
    },
    "entity-matcher.integration-overview": {
      path: "images/backoffice/configuration/entity-matcher/integration-overview.png",
      caption: "The Entity Matcher is accessed from the overview page of a System Integration.",
      w: 2880,
      h: 1800
    },
    "entity-matcher.filter-form": {
      path: "images/backoffice/configuration/entity-matcher/filter-form.png",
      caption: "Select a domain and match field before searching for entity matches.",
      w: 1536,
      h: 300
    },
    "entity-matcher.search-results": {
      path: "images/backoffice/configuration/entity-matcher/search-results.png",
      caption: "Local entities on the left, remote candidate entities in the dropdowns on the right.",
      w: 1536,
      h: 800
    },
    "integrations.alexis_hr.system-settings": {
      path: "images/integrations/screenshots/alexis_hr/system-settings.png",
      caption: "The system-specific settings tab for Alexis HR on its configured integration.",
      w: 2880,
      h: 1800
    },
    "jobs.list": {
      path: "images/backoffice/daily-operations/jobs/list.png",
      caption: "The Jobs page shows sync jobs with their type, domain, status, and creation time.",
      w: 2880,
      h: 1800
    },
    "notifications.settings": {
      path: "images/backoffice/configuration/notifications/settings.png",
      caption: "Notification settings control which events trigger alerts and who receives them.",
      w: 2880,
      h: 1800
    },
    "roles.list": {
      path: "images/backoffice/configuration/roles/list.png",
      caption: "The Roles page lets you define roles and the rules that govern access within an organization.",
      w: 2880,
      h: 1800
    },
    "roles.quick-start-wizard": {
      path: "images/backoffice/configuration/roles/quick-start-wizard.png",
      caption: "The Quick start wizard creates a preconfigured Org admin or Org user role in one step.",
      w: 1060,
      h: 928
    },
    "roles.detail-sheet": {
      path: "images/backoffice/configuration/roles/detail-sheet.png",
      caption: "Clicking a role opens a detail sheet showing metadata, tokens, and a link to manage rules.",
      w: 2880,
      h: 1800
    },
    "roles.rules-page": {
      path: "images/backoffice/configuration/roles/rules-page.png",
      caption: "The rules page shows all rules for a role. Expanding a rule reveals its TERLs.",
      w: 2880,
      h: 1800
    },
    "roles.edit-rule": {
      path: "images/backoffice/configuration/roles/edit-rule.png",
      caption: "The rule editor lets you configure a rule name, policy, actions, and TERLs.",
      w: 1344,
      h: 1232
    },
    "roles.tokens-add-form": {
      path: "images/backoffice/configuration/roles/tokens-add-form.png",
      caption: "Add a new API or refresh token to a role by filling in the name and type.",
      w: 1344,
      h: 1800
    },
    "roles.token-created": {
      path: "images/backoffice/configuration/roles/token-created.png",
      caption: "After creating a token, copy it immediately — it is only shown once.",
      w: 1344,
      h: 1800
    },
    "roles.tokens-list": {
      path: "images/backoffice/configuration/roles/tokens-list.png",
      caption: "The Tokens table shows every active API and refresh token for the role.",
      w: 1344,
      h: 1800
    },
    "roles.token-revoked": {
      path: "images/backoffice/configuration/roles/token-revoked.png",
      caption: "Revoking a token immediately invalidates it. Revoked tokens disappear from the list.",
      w: 1344,
      h: 1800
    },
    "roles.add-terl": {
      path: "images/backoffice/configuration/roles/add-terl.png",
      caption: "Click \"Add new TERL\" to add a resource target to a rule.",
      w: 1344,
      h: 1536
    },
    "system-data.employee-detail": {
      path: "images/backoffice/data/system-data/employee-detail.png",
      caption: "Selecting an employee opens a detail view with properties, metadata, and source data inspection tools.",
      w: 2880,
      h: 1800
    },
    "system-data.time-reports-employee": {
      path: "images/backoffice/data/system-data/time-reports-employee.png",
      caption: "Filter time reports by employee and date range to see reported time across a specific period.",
      w: 2880,
      h: 1800
    },
    "system-data.employees-list": {
      path: "images/backoffice/data/system-data/employees-list.png",
      caption: "The Employees table shows every employee ingested from the connected source systems.",
      w: 2880,
      h: 1800
    },
    "system-data.time-reports": {
      path: "images/backoffice/data/system-data/time-reports.png",
      caption: "Time Reports displays a calendar-style grid of reported time, grouped by employee or time code.",
      w: 2880,
      h: 1800
    },
    "system-integration-settings.metadata": {
      path: "images/backoffice/configuration/system-integration-settings/metadata.png",
      caption: "The Metadata sub-tab shows system-specific metadata fetched from the source system.",
      w: 2880,
      h: 1800
    },
    "templates.list": {
      path: "images/backoffice/configuration/templates/list.png",
      caption: "Mapping Templates define how data from a source system is mapped into Twine.",
      w: 2880,
      h: 1800
    }
  };
  const shot = screenshots[id];
  if (!shot) return <div style={{
    color: '#dc2626',
    padding: '12px',
    border: '1px solid #dc2626',
    borderRadius: '6px',
    fontSize: '13px',
    margin: '24px 0'
  }}>
      Screenshot not found: <code>{id}</code>
    </div>;
  if (!shot.highlights || shot.highlights.length === 0) return <div style={{
    color: '#dc2626',
    padding: '12px',
    border: '1px solid #dc2626',
    borderRadius: '6px',
    fontSize: '13px',
    margin: '24px 0'
  }}>
      No highlights defined for: <code>{id}</code>
    </div>;
  const keyToIndex = {};
  shot.highlights.forEach((hl, i) => {
    keyToIndex[hl.key] = i;
  });
  const authoredChildren = children ? (Array.isArray(children) ? children : [children]).filter(Boolean) : [];
  const authoredMap = {};
  authoredChildren.forEach(child => {
    if (child && child.props && child.props.highlightKey) {
      authoredMap[child.props.highlightKey] = child.props.children;
    }
  });
  const hoverRules = shot.highlights.map(hl => '.as-container:has(.as-callout-' + hl.key + ':hover) .as-hl-' + hl.key + ' { opacity: 1; border-color: var(--colors-primary, #7600ff); }').join('\n    ');
  return <>
      <style>{`
        .as-container {
          display: grid;
          grid-template-columns: 3fr 2fr;
          gap: 24px;
          align-items: start;
          margin: 24px 0;
        }
        .as-image-col {
          position: sticky;
          top: 80px;
          max-height: calc(100vh - 100px);
          overflow: auto;
        }
        .as-image-wrap {
          position: relative;
          width: 100%;
          padding: 0;
          font-size: 0;
          line-height: 0;
          border-radius: 8px;
          overflow: hidden;
          border: 1px solid rgb(var(--primary-light) / .15);
          box-shadow: 0 1px 3px rgb(0 0 0 / .06);
        }
        .as-image-wrap > img {
          position: absolute;
          inset: 0;
          display: block;
          width: 100%;
          height: 100%;
          object-fit: fill;
          padding: 0;
          margin: 0;
          border: 0;
        }
        .as-highlight {
          position: absolute;
          border: 2px solid rgb(var(--primary-light) / .6);
          border-radius: 4px;
          opacity: 0.35;
          transition: opacity 0.2s ease, border-color 0.2s ease;
          pointer-events: none;
          transform: translate(-8px, -8px);
          padding: 8px;
          box-sizing: content-box;
        }
        .as-highlight-badge {
          position: absolute;
          top: -10px;
          left: -10px;
          width: 20px;
          height: 20px;
          border-radius: 50%;
          background: var(--colors-primary, #7600ff);
          color: #fff;
          font-size: 11px;
          font-weight: 700;
          display: flex;
          align-items: center;
          justify-content: center;
          pointer-events: none;
        }
        .as-callout-col {
          display: flex;
          flex-direction: column;
          gap: 12px;
          padding: 8px 0;
        }
        .as-callout:hover {
          border-color: var(--colors-primary, #7600ff) !important;
          background: rgb(var(--primary-light) / .08) !important;
        }
        ${hoverRules}
        @media (max-width: 720px) {
          .as-container {
            grid-template-columns: 1fr;
          }
          .as-image-col {
            position: static;
            max-height: none;
            overflow: visible;
          }
        }
      `}</style>
      <div className="as-container">
        <div className="as-image-col">
          <div className="as-image-wrap" style={{
    aspectRatio: `${shot.w} / ${shot.h}`
  }}>
            <img src={`/${shot.path}`} alt={shot.caption || ''} style={{
    position: 'absolute',
    inset: 0,
    display: 'block',
    width: '100%',
    height: '100%',
    objectFit: 'fill'
  }} />
            {shot.highlights.map((hl, i) => <div key={hl.key} className={`as-highlight as-hl-${hl.key}`} style={{
    left: hl.x * 100 + '%',
    top: hl.y * 100 + '%',
    width: hl.w * 100 + '%',
    height: hl.h * 100 + '%'
  }}>
                <span className="as-highlight-badge">{i + 1}</span>
              </div>)}
          </div>
          {shot.caption && <div style={{
    marginTop: '8px',
    fontSize: '13px',
    color: 'var(--colors-content-secondary, #6b7280)',
    textAlign: 'center',
    fontStyle: 'italic'
  }}>
              {shot.caption}
            </div>}
        </div>
        <div className="as-callout-col">
          {shot.highlights.map((hl, i) => <div key={hl.key} className={`as-callout as-callout-${hl.key}`} style={{
    display: 'flex',
    gap: '12px',
    padding: '14px 16px',
    borderRadius: '8px',
    border: '1px solid rgb(var(--primary-light) / .15)',
    background: 'rgb(var(--primary-light) / .04)',
    cursor: 'default',
    transition: 'border-color 0.15s, background 0.15s'
  }}>
              <span style={{
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    width: '24px',
    height: '24px',
    borderRadius: '50%',
    background: 'var(--colors-primary, #7600ff)',
    color: '#fff',
    fontSize: '12px',
    fontWeight: 700,
    flexShrink: 0
  }}>
                {i + 1}
              </span>
              <div style={{
    fontSize: '14px',
    lineHeight: 1.5,
    color: 'inherit'
  }}>
                {authoredMap[hl.key] || hl.description}
              </div>
            </div>)}
        </div>
      </div>
    </>;
};

export const Shot = ({id, caption}) => {
  const screenshots = {
    "domain-mappings.sync-trigger-actions-employee": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-actions-employee.png",
      caption: "Each sync trigger exposes action buttons for an ad-hoc sync and for editing the trigger configuration.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "sync-now",
        description: "Fires an immediate one-off sync without waiting for the next scheduled run. Handy when you want to see the effect of a configuration change right away.",
        x: 0.8854,
        y: 0.5056,
        w: 0.025,
        h: 0.0511
      }, {
        key: "edit",
        description: "Opens the edit modal where the schedule, parent trigger, scheduled toggles, and any domain-specific settings for this trigger can be adjusted.",
        x: 0.916,
        y: 0.5056,
        w: 0.025,
        h: 0.04
      }]
    },
    "domain-mappings.sync-trigger-edit-employee": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-edit-employee.png",
      caption: "The Edit Sync Trigger modal for a non-time-report mapping.",
      w: 900,
      h: 1124,
      highlights: [{
        key: "cron-enabled",
        description: "Controls whether the trigger fires automatically. When it is turned off, the trigger only runs if someone starts it manually.",
        x: 0.0556,
        y: 0.3149,
        w: 0.2336,
        h: 0.0783
      }, {
        key: "cron-expression",
        description: "Standard cron syntax that determines when the trigger runs while the schedule is enabled.",
        x: 0.3247,
        y: 0.3149,
        w: 0.6198,
        h: 0.1103
      }, {
        key: "scheduled-toggles",
        description: "Queues future flips of the enable state. Useful for pausing a trigger during a maintenance window and having it re-enable itself afterwards without manual intervention.",
        x: 0.0556,
        y: 0.468,
        w: 0.8889,
        h: 0.2349
      }, {
        key: "parent-trigger",
        description: "Chains this trigger to run immediately after another one completes, so dependent syncs always happen in the right order.",
        x: 0.0556,
        y: 0.7456,
        w: 0.8889,
        h: 0.1032
      }]
    },
    "domain-mappings.sync-trigger-actions-time-report": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-actions-time-report.png",
      caption: "Time-report mappings expose the same sync trigger actions as other domains.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "sync-now",
        description: "Fires an immediate sync. On time-report mappings this first opens a small dialog for picking the date range to pull before the sync actually runs.",
        x: 0.8854,
        y: 0.5056,
        w: 0.025,
        h: 0.0511
      }, {
        key: "edit",
        description: "Opens the edit modal. For a time-report mapping this exposes an extra section for the default date range the scheduled sync should cover.",
        x: 0.916,
        y: 0.5056,
        w: 0.025,
        h: 0.04
      }]
    },
    "domain-mappings.sync-trigger-edit-time-report": {
      path: "images/backoffice/configuration/domain-mappings/sync-trigger-edit-time-report.png",
      caption: "The Edit Sync Trigger modal for a time-report mapping exposes an extra date-range section.",
      w: 900,
      h: 1388,
      highlights: [{
        key: "cron-enabled",
        description: "Controls whether the trigger fires automatically. When it is turned off, the trigger only runs if someone starts it manually.",
        x: 0.0556,
        y: 0.255,
        w: 0.2336,
        h: 0.0634
      }, {
        key: "cron-expression",
        description: "Standard cron syntax that determines when the trigger runs while the schedule is enabled.",
        x: 0.3247,
        y: 0.255,
        w: 0.6198,
        h: 0.0893
      }, {
        key: "scheduled-toggles",
        description: "Queues future flips of the enable state. Useful for pausing a trigger during a maintenance window and having it re-enable itself afterwards without manual intervention.",
        x: 0.0556,
        y: 0.379,
        w: 0.8889,
        h: 0.1902
      }, {
        key: "parent-trigger",
        description: "Chains this trigger to run immediately after another one completes, so dependent syncs always happen in the right order.",
        x: 0.0556,
        y: 0.6037,
        w: 0.8889,
        h: 0.0836
      }, {
        key: "time-report-settings",
        description: "Defines which date range the sync should pull time reports for. The start and end dates can each be either a fixed date or a dynamic expression evaluated at run time.",
        x: 0.0556,
        y: 0.7219,
        w: 0.8889,
        h: 0.1556
      }]
    },
    "domain-mappings.employee-outgoing": {
      path: "images/backoffice/configuration/domain-mappings/employee-outgoing.png",
      caption: "An outgoing Employee → Employee mapping pushes Twine employee data into a target system.",
      w: 2880,
      h: 1800
    },
    "domain-mappings.time-report": {
      path: "images/backoffice/configuration/domain-mappings/time-report.png",
      caption: "Time report mappings include a dedicated time-code mapping section alongside the standard configuration.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "time-code-mapping",
        description: "Appears only on time report to time report mappings. Lines up each time code in the source system with the matching Twine time code so reported hours land in the right bucket downstream.",
        x: 0.1778,
        y: 0.4256,
        w: 0.4,
        h: 0.5567
      }]
    },
    "jobs.details": {
      path: "images/backoffice/daily-operations/jobs/details.png",
      caption: "The Job Details page shows everything about a single sync job — its metadata, status, descendants, and streaming logs.",
      w: 2880,
      h: 1800
    },
    "system-integration-settings.authentication": {
      path: "images/backoffice/configuration/system-integration-settings/authentication.png",
      caption: "The Authentication sub-tab holds credentials and a sharable authentication URL generator.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "generate-url-button",
        description: "Generates a one-time shareable URL that lets a customer without a Twine login enter their own credentials. The link stays valid for five days.",
        x: 0.816,
        y: 0.3378,
        w: 0.1555,
        h: 0.04
      }]
    },
    "system-integration-settings.authentication-url-generated": {
      path: "images/backoffice/configuration/system-integration-settings/authentication-url-generated.png",
      caption: "After clicking Generate Authentication URL, the card displays the shareable link with a copy button.",
      w: 872,
      h: 948,
      highlights: [{
        key: "copy-button",
        description: "Copies the generated link to the clipboard so it can be pasted into an email or chat to the customer.",
        x: 0.8945,
        y: 0.692,
        w: 0.0275,
        h: 0.0253
      }]
    },
    "system-integration-settings.general": {
      path: "images/backoffice/configuration/system-integration-settings/general.png",
      caption: "The General sub-tab holds system-specific settings that are not credentials.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "system-specific-card",
        description: "Holds configuration that is specific to the connected system and unrelated to authentication. The exact fields depend on which integration is selected.",
        x: 0.6861,
        y: 0.2633,
        w: 0.3028,
        h: 0.28
      }]
    },
    "system-integration-settings.time-reports": {
      path: "images/backoffice/configuration/system-integration-settings/time-reports.png",
      caption: "The Time Reports & Types sub-tab configures how source time codes map to Twine time codes.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "refresh-button",
        description: "Re-fetches the current time-type catalogue from the connected system so the mapping list picks up anything that has been added or removed upstream.",
        x: 0.3896,
        y: 0.9144,
        w: 0.1529,
        h: 0.04
      }]
    },
    "system-integrations.admin": {
      path: "images/backoffice/configuration/system-integrations/admin.png",
      caption: "The Admin tab exposes destructive and one-shot administrative actions for a system integration.",
      w: 2880,
      h: 1800
    },
    "system-integrations.domains-overview": {
      path: "images/backoffice/configuration/system-integrations/domains-overview.png",
      caption: "The Domains tab lists outgoing and incoming domain mappings for this system integration.",
      w: 2880,
      h: 1800,
      highlights: [{
        key: "create-button",
        description: "Opens a dialog where you pick the direction, target integration, and source and target domains for a new mapping.",
        x: 0.8297,
        y: 0.2633,
        w: 0.1592,
        h: 0.04
      }]
    },
    "system-integrations.domains-create-dialog": {
      path: "images/backoffice/configuration/system-integrations/domains-create-dialog.png",
      caption: "The Create Domain Mapping dialog starts with the direction radio and an empty form.",
      w: 900,
      h: 964
    },
    "system-integrations.domains-create-dialog-filled": {
      path: "images/backoffice/configuration/system-integrations/domains-create-dialog-filled.png",
      caption: "Once a target system integration and source/target domains are selected, the Create button unlocks.",
      w: 900,
      h: 964
    },
    "anomalies.list": {
      path: "images/backoffice/daily-operations/anomalies/list.png",
      caption: "The Anomalies page lists issues grouped by severity, system, and status.",
      w: 2880,
      h: 1800
    },
    "entity-matcher.integration-overview": {
      path: "images/backoffice/configuration/entity-matcher/integration-overview.png",
      caption: "The Entity Matcher is accessed from the overview page of a System Integration.",
      w: 2880,
      h: 1800
    },
    "entity-matcher.filter-form": {
      path: "images/backoffice/configuration/entity-matcher/filter-form.png",
      caption: "Select a domain and match field before searching for entity matches.",
      w: 1536,
      h: 300
    },
    "entity-matcher.search-results": {
      path: "images/backoffice/configuration/entity-matcher/search-results.png",
      caption: "Local entities on the left, remote candidate entities in the dropdowns on the right.",
      w: 1536,
      h: 800
    },
    "integrations.alexis_hr.system-settings": {
      path: "images/integrations/screenshots/alexis_hr/system-settings.png",
      caption: "The system-specific settings tab for Alexis HR on its configured integration.",
      w: 2880,
      h: 1800
    },
    "jobs.list": {
      path: "images/backoffice/daily-operations/jobs/list.png",
      caption: "The Jobs page shows sync jobs with their type, domain, status, and creation time.",
      w: 2880,
      h: 1800
    },
    "notifications.settings": {
      path: "images/backoffice/configuration/notifications/settings.png",
      caption: "Notification settings control which events trigger alerts and who receives them.",
      w: 2880,
      h: 1800
    },
    "roles.list": {
      path: "images/backoffice/configuration/roles/list.png",
      caption: "The Roles page lets you define roles and the rules that govern access within an organization.",
      w: 2880,
      h: 1800
    },
    "roles.quick-start-wizard": {
      path: "images/backoffice/configuration/roles/quick-start-wizard.png",
      caption: "The Quick start wizard creates a preconfigured Org admin or Org user role in one step.",
      w: 1060,
      h: 928
    },
    "roles.detail-sheet": {
      path: "images/backoffice/configuration/roles/detail-sheet.png",
      caption: "Clicking a role opens a detail sheet showing metadata, tokens, and a link to manage rules.",
      w: 2880,
      h: 1800
    },
    "roles.rules-page": {
      path: "images/backoffice/configuration/roles/rules-page.png",
      caption: "The rules page shows all rules for a role. Expanding a rule reveals its TERLs.",
      w: 2880,
      h: 1800
    },
    "roles.edit-rule": {
      path: "images/backoffice/configuration/roles/edit-rule.png",
      caption: "The rule editor lets you configure a rule name, policy, actions, and TERLs.",
      w: 1344,
      h: 1232
    },
    "roles.tokens-add-form": {
      path: "images/backoffice/configuration/roles/tokens-add-form.png",
      caption: "Add a new API or refresh token to a role by filling in the name and type.",
      w: 1344,
      h: 1800
    },
    "roles.token-created": {
      path: "images/backoffice/configuration/roles/token-created.png",
      caption: "After creating a token, copy it immediately — it is only shown once.",
      w: 1344,
      h: 1800
    },
    "roles.tokens-list": {
      path: "images/backoffice/configuration/roles/tokens-list.png",
      caption: "The Tokens table shows every active API and refresh token for the role.",
      w: 1344,
      h: 1800
    },
    "roles.token-revoked": {
      path: "images/backoffice/configuration/roles/token-revoked.png",
      caption: "Revoking a token immediately invalidates it. Revoked tokens disappear from the list.",
      w: 1344,
      h: 1800
    },
    "roles.add-terl": {
      path: "images/backoffice/configuration/roles/add-terl.png",
      caption: "Click \"Add new TERL\" to add a resource target to a rule.",
      w: 1344,
      h: 1536
    },
    "system-data.employee-detail": {
      path: "images/backoffice/data/system-data/employee-detail.png",
      caption: "Selecting an employee opens a detail view with properties, metadata, and source data inspection tools.",
      w: 2880,
      h: 1800
    },
    "system-data.time-reports-employee": {
      path: "images/backoffice/data/system-data/time-reports-employee.png",
      caption: "Filter time reports by employee and date range to see reported time across a specific period.",
      w: 2880,
      h: 1800
    },
    "system-data.employees-list": {
      path: "images/backoffice/data/system-data/employees-list.png",
      caption: "The Employees table shows every employee ingested from the connected source systems.",
      w: 2880,
      h: 1800
    },
    "system-data.time-reports": {
      path: "images/backoffice/data/system-data/time-reports.png",
      caption: "Time Reports displays a calendar-style grid of reported time, grouped by employee or time code.",
      w: 2880,
      h: 1800
    },
    "system-integration-settings.metadata": {
      path: "images/backoffice/configuration/system-integration-settings/metadata.png",
      caption: "The Metadata sub-tab shows system-specific metadata fetched from the source system.",
      w: 2880,
      h: 1800
    },
    "templates.list": {
      path: "images/backoffice/configuration/templates/list.png",
      caption: "Mapping Templates define how data from a source system is mapped into Twine.",
      w: 2880,
      h: 1800
    }
  };
  const shot = screenshots[id];
  if (!shot) return <div style={{
    color: '#dc2626',
    padding: '12px',
    border: '1px solid #dc2626',
    borderRadius: '6px',
    fontSize: '13px',
    margin: '24px 0'
  }}>
      Screenshot not found: <code>{id}</code>
    </div>;
  const displayCaption = caption || shot.caption;
  return <figure style={{
    margin: '24px 0'
  }}>
      <img src={`/${shot.path}`} alt={displayCaption || ''} style={{
    width: '100%',
    height: 'auto',
    borderRadius: '8px',
    border: '1px solid rgb(var(--primary-light) / .15)',
    boxShadow: '0 1px 3px rgb(0 0 0 / .06)',
    display: 'block'
  }} />
      {displayCaption && <figcaption style={{
    marginTop: '8px',
    fontSize: '13px',
    color: 'var(--colors-content-secondary, #6b7280)',
    textAlign: 'center',
    fontStyle: 'italic'
  }}>
          {displayCaption}
        </figcaption>}
    </figure>;
};

A [System Integration](/platform/system-integrations) is configured through a tabbed interface in the backoffice. This page covers the **Settings** and **Admin** tabs. For other tabs, see:

* [Entity Matcher](/backoffice/configuration/entity-matcher) (Overview tab)
* [Domain Mappings](/backoffice/configuration/domain-mappings) (Domains tab)

## Settings

The Settings tab is split into subtabs. The exact subtabs shown depend on the system being configured.

### Authentication

The Authentication subtab holds the credentials and connection details for the integration. The specific fields vary per system.

A key feature is the **authentication URL generator**: it creates a sharable, time-limited URL that can be sent to a customer so they can enter their own credentials without needing access to the Twine backoffice.

<AnnotatedShot id="system-integration-settings.authentication" />

After generating the URL, a card appears with the link and a copy button. The URL is valid for 5 days (120 hours).

<AnnotatedShot id="system-integration-settings.authentication-url-generated" />

### General

The General subtab holds settings that are not credentials. The left side contains settings common to all integrations; the right side contains system-specific configuration whose fields vary per integration.

<AnnotatedShot id="system-integration-settings.general" />

### Metadata

The Metadata subtab displays read-only metadata fetched from the source system - useful reference when configuring property mappings or debugging data issues.

<Shot id="system-integration-settings.metadata" />

### Time Reports and Types

This subtab is shown for systems that handle time reports. It displays the time-type catalogue fetched from the remote system. These types are used later when linking time codes from two different systems together in a [domain mapping](/backoffice/configuration/domain-mappings).

<AnnotatedShot id="system-integration-settings.time-reports" />

## Admin

The Admin tab exposes destructive operations for this system integration. These are one-shot actions that cannot be undone.

<Shot id="system-integrations.admin" />

The available actions are:

* **Delete integration** - permanently removes this system integration and all its configuration.
* **Reset property mappings** - reverts all property mappings for this system to factory defaults. Useful when starting over from a template or after a misconfiguration.
* **Delete data** - removes all entities (employees, time reports, etc.) that have been stored from this integration. The integration configuration itself is preserved.
