EU Data Act Cloud Switching 2026: Parallel Operations, Transition Assistance & Provider Cooperation Architecture
Post #1419 in the sota.io EU Cloud Compliance Series
The EU Data Act cloud switching obligation is not a point-in-time export event — it is an active transition period during which both the outgoing provider and, where technically feasible, the incoming provider have overlapping legal obligations. Article 24 of Regulation (EU) 2023/2854 introduces switching assistance: a structured handover protocol that requires the outgoing provider to actively support continuity of service during the customer's move.
This is the fourth post in our EU-DATA-ACT-CLOUD-SWITCHING-2026 series. The first post covered the switching request API and the 30-day state machine. The second post covered data format standards and interoperability. The third post covered Art.27 prohibitions on obstacles and lock-in patterns. This post covers the transition architecture: how to build a compliant parallel operations system and what switching assistance means in code.
What Art.24 Actually Requires
Article 24 of the EU Data Act requires providers of data processing services to offer switching assistance — a set of support obligations that begins when the customer initiates the switch and continues through the transition period. The provision distinguishes between two categories:
Assistance to the Switching Customer
The outgoing provider must:
- Provide complete export of all customer data in the agreed format (see Art.23 and the format post)
- Maintain the customer's data in a readable, accessible state throughout the transition window — service degradation during this period violates Art.27
- Provide technical documentation sufficient for the receiving provider to replicate the customer's configuration, integrations, and workflows
- Respond to reasonable technical queries from the customer or their designated receiving provider within a timeframe proportionate to the complexity of the query
Assistance to the Receiving Provider
Where the customer authorises it, the outgoing provider must cooperate directly with the receiving provider. This cooperation obligation is new in EU law — prior data portability rights (e.g., under GDPR Art.20) created no obligation to engage with the receiving party. Under Art.24, the outgoing provider must:
- Accept and respond to a formally designated receiving provider identified by the customer
- Provide technical metadata that enables the receiving provider to import the customer's data without requiring reverse engineering of proprietary schemas
- Participate in a synchronisation window where changes made by the customer on the outgoing platform are mirrored or communicated to the receiving platform
The synchronisation obligation applies only where "technically feasible" — a standard that will be interpreted by NCAs based on the provider's technical capabilities, not self-declaration.
Parallel Operations Architecture
The operational challenge for most SaaS platforms is that customers rarely switch cleanly: they run both platforms simultaneously for days or weeks, updating records on one while the other is being configured. Art.24 implicitly anticipates this by requiring the outgoing provider to communicate changes during the transition window.
The Three-Phase Transition Model
A compliant transition has three phases:
enum SwitchingPhase {
EXPORT_PREPARATION = 'export_preparation', // Days 1-5: prepare full data export
PARALLEL_OPERATION = 'parallel_operation', // Days 5-30: dual-write + sync
CUTOVER = 'cutover', // Day 30: final export, service end
}
interface TransitionState {
customerId: string;
phase: SwitchingPhase;
switchInitiatedAt: Date;
exportCompletedAt?: Date;
parallelStartedAt?: Date;
cutovertAt?: Date;
receivingProviderEndpoint?: string;
receivingProviderAuthorised: boolean;
}
Phase 1: Export Preparation (Days 1-5)
The outgoing provider generates the full data export in the formats requested by the customer. This must be a point-in-time consistent snapshot. For large datasets, multi-part chunked exports are acceptable provided the snapshot timestamp is consistent across chunks.
async function initiateExportPreparation(
customerId: string,
requestedFormats: ExportFormat[]
): Promise<ExportJob> {
const snapshotTimestamp = new Date();
const job = await db.exportJobs.create({
customerId,
snapshotAt: snapshotTimestamp,
formats: requestedFormats,
status: 'preparing',
estimatedCompletionAt: addBusinessDays(snapshotTimestamp, 5),
});
// All subsequent exports use snapshotTimestamp for consistency
await queue.enqueue('export-customer-data', {
jobId: job.id,
customerId,
snapshotAt: snapshotTimestamp.toISOString(),
formats: requestedFormats,
});
return job;
}
Phase 2: Parallel Operation (Days 5-30)
This is the most complex phase. The customer is actively using both platforms. The outgoing provider must communicate changes to the receiving provider (if authorised by the customer) so that the receiving platform can maintain a near-current view of the customer's data.
The communication can take two forms:
- Push-based (preferred): The outgoing platform posts incremental change events to a webhook provided by the receiving provider
- Pull-based (acceptable): The receiving provider polls a delta API on the outgoing platform, receiving changes since a given cursor
interface ChangeEvent {
eventId: string;
eventType: 'create' | 'update' | 'delete';
entityType: string;
entityId: string;
timestamp: string;
payload: Record<string, unknown>;
schemaVersion: string;
}
class TransitionSyncService {
private receivingWebhookUrl: string;
private customerId: string;
private signingKey: string;
async publishChange(event: ChangeEvent): Promise<void> {
const signature = await this.signPayload(JSON.stringify(event));
await fetch(this.receivingWebhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Dataact-Signature': signature,
'X-Customer-Id': this.customerId,
'X-Event-Id': event.eventId,
},
body: JSON.stringify(event),
});
}
async publishBatch(events: ChangeEvent[]): Promise<void> {
// Batch endpoint for high-volume changes during parallel period
const signature = await this.signPayload(JSON.stringify(events));
await fetch(`${this.receivingWebhookUrl}/batch`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Dataact-Signature': signature,
'X-Customer-Id': this.customerId,
'X-Batch-Size': String(events.length),
},
body: JSON.stringify(events),
});
}
private async signPayload(payload: string): Promise<string> {
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
'raw', encoder.encode(this.signingKey),
{ name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
);
const sig = await crypto.subtle.sign('HMAC', key, encoder.encode(payload));
return Buffer.from(sig).toString('base64');
}
}
Phase 3: Cutover (Day 30)
At cutover, the outgoing provider:
- Generates a final delta export covering all changes since the snapshot export
- Ceases publishing change events
- Begins the service termination sequence (but must not delete data until the retention period expires)
async function executeCutover(customerId: string): Promise<CutoverResult> {
const transition = await db.transitions.findByCustomer(customerId);
// Final delta export
const deltaExport = await generateDeltaExport(
customerId,
transition.snapshotAt,
new Date()
);
// Stop sync
await db.transitions.update(customerId, {
phase: SwitchingPhase.CUTOVER,
cutovertAt: new Date(),
syncActive: false,
});
// Notify receiving provider of cutover completion
if (transition.receivingProviderEndpoint) {
await notifyCutoverComplete(
transition.receivingProviderEndpoint,
customerId,
deltaExport.exportId
);
}
return { success: true, deltaExportId: deltaExport.exportId };
}
Provider Cooperation API: What to Expose
The Art.24 cooperation obligation requires you to provide a machine-readable interface that an authorised receiving provider can call. This is distinct from the customer-facing export API. The provider cooperation interface must support:
1. Transition Authorisation Endpoint
// POST /v1/switching/authorize-receiver
interface ReceiverAuthRequest {
customerId: string;
customerAuthToken: string; // Customer-signed JWT proving consent
receiverIdentity: {
name: string;
euVatNumber?: string;
contactEmail: string;
webhookEndpoint: string; // Where to push change events
webhookSecret: string; // For HMAC verification
};
}
interface ReceiverAuthResponse {
transitionId: string;
authorisedAt: string;
syncStartsAt: string; // When Phase 2 begins
exportAvailableAt: string; // When Phase 1 export is ready
deltaApiEndpoint: string; // Pull API endpoint for receiving provider
}
2. Delta Change API
// GET /v1/switching/{transitionId}/changes?since={cursor}&limit={n}
interface DeltaResponse {
transitionId: string;
customerId: string;
cursor: string; // Opaque pagination cursor
hasMore: boolean;
events: ChangeEvent[];
generatedAt: string;
}
3. Metadata Export Endpoint
The metadata export provides the receiving provider with schema information, integration configurations, and environment metadata — things that are not part of the customer's data but are necessary to replicate the customer's setup.
// GET /v1/switching/{transitionId}/metadata
interface TransitionMetadata {
schemaVersion: string;
exportedAt: string;
dataModels: DataModelDescriptor[];
integrations: IntegrationConfig[];
webhookSubscriptions: WebhookDescriptor[];
customFields: CustomFieldDefinition[];
permissionSchemas: PermissionSchema[];
}
Compliance Pitfalls in the Parallel Operations Period
Pitfall 1: Failing to Maintain Service Quality During Sync
Some providers reduce API rate limits or disable integrations once a switching request is active. Under Art.27 this is a prohibited obstacle. The switching request must not change the customer's service tier or API access.
// WRONG: Throttling API calls during transition
async function handleApiRequest(customerId: string, req: Request): Promise<Response> {
const transition = await getTransition(customerId);
if (transition?.isActive) {
// DO NOT DO THIS — Art.27 violation
return rateLimitResponse('API access reduced during transition');
}
return processRequest(req);
}
// CORRECT: Service continues unchanged
async function handleApiRequest(customerId: string, req: Request): Promise<Response> {
// No branch on transition status for service access
return processRequest(req);
}
Pitfall 2: Incomplete Delta Events
Delta events must cover all entity types that were included in the initial export. If the initial export included invoices, contacts, projects, and files, the delta feed must include events for all four entity types. Selective delta feeds that omit less-used entity types are non-compliant — the receiving provider will receive an inconsistent view of the customer's data.
Pitfall 3: Missing Deletion Events
Customers delete records during the transition period. If your delta feed omits deletion events, the receiving provider will have records that no longer exist at the outgoing provider. After cutover, the customer's data will appear corrupted. Deletion events are mandatory.
interface DeleteEvent extends ChangeEvent {
eventType: 'delete';
payload: {
deletedAt: string;
deletedBy: 'user' | 'system' | 'api';
retentionExpiry?: string; // When outgoing provider will physically delete
};
}
Pitfall 4: Synchronous Cutover Without Delta Export
Some implementations treat cutover as an atomic event — they terminate the sync and simultaneously hand over the export, with no mechanism for the receiving provider to reconcile changes that occurred during the delivery latency. The correct approach generates a delta export covering the window between the snapshot export timestamp and the cutover event, ensuring no changes are lost.
What NCAs Look for in Transition Audits
National competent authorities enforcing the EU Data Act cloud switching provisions have begun auditing providers on the parallel operations period. The audit typically includes:
Documentation review:
- Does the provider have a written switching assistance policy?
- Is the policy consistent with Art.24 obligations?
- Does the policy cover both customer-facing and receiver-facing assistance?
Technical review:
- Can the provider demonstrate a working delta API?
- Are deletion events included in the delta feed?
- Is service quality maintained during the switching window (API rate limits, integrations)?
Customer complaint analysis:
- Has the provider received complaints about transition data loss?
- How were complaints resolved?
Stress test (for large providers):
- The NCA may request a test switching event using anonymised data to verify that the parallel operations system functions as documented
Integration with Your Existing Compliance Stack
If you have implemented the Art.23 switching request API from the first post in this series, the parallel operations system integrates at the state machine level:
// Extend the switching state machine with Phase 2 transitions
const switchingMachine = createMachine({
states: {
idle: {
on: { SWITCH_REQUESTED: 'export_preparation' }
},
export_preparation: {
on: { EXPORT_COMPLETE: 'parallel_operation' },
after: { [5 * DAY_MS]: 'export_preparation' } // SLA reminder
},
parallel_operation: {
entry: ['startDeltaSync', 'notifyReceivingProvider'],
on: { CUTOVER_REQUESTED: 'cutover' },
after: { [30 * DAY_MS]: 'cutover' } // Auto-cutover at deadline
},
cutover: {
entry: ['stopDeltaSync', 'generateFinalDelta', 'notifyCutoverComplete'],
on: { CUTOVER_COMPLETE: 'completed' }
},
completed: {
type: 'final'
}
}
});
Next in This Series
The fifth and final post in this series will be the complete developer toolkit: a checklist covering Art.23-28 compliance, the NCA enforcement timeline by member state, how to estimate your risk exposure, and a reference architecture for a fully compliant switching stack.
Series navigation:
- Post 1: Technical Implementation Guide
- Post 2: Data Format Standards & Interoperability
- Post 3: Art.27 Lock-In Compliance
- Post 4: Parallel Operations & Transition Assistance (this post)
- Post 5: Complete Developer Toolkit (coming next)
EU-Native Hosting
Ready to move to EU-sovereign infrastructure?
sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.