Bill Switch / Deposit Switch

Important

Bill Switch and Deposit Switch are only available to Credit Builder Card users.

Upward has partnered with Atomic to automatically Switch Bill Pay and deposit functionality to your Consumer’s Payment Cards. In this updated flow, you will first request either a Bill Switch or Deposit Switch token from the Upward API platform, and then use that Token to initialize the Atomic SDK. Once a connection is successful, you will receive regular updates/webhooks directly from Atomic as per their documentation.

Requesting a Bill Switch Token

Request a Bill Switch Token by calling POST /v2/payment-cards/{payment_card_id}/bill-switch/token. You will use this token to initialize the Atomic client-side SDK.

Response:

1{
2 "public_token": "string"
3}

You can view more details about the Deposit Switch endpoint here

Requesting a Deposit Switch Token

Request a Deposit Switch Token by calling POST /v2/payment-cards/{payment_card_id}/deposit-switch/token. You will use this token to initialize the Atomic client-side SDK.

Response:

1{
2 "public_token": "string"
3}

You can view more details about the Deposit Switch endpoint here

Atomic Financial

For more on the Atomic Switch Product, view the documentation here.


Integration Steps

Once you have obtained the token from Upwardli’s bill-switch or deposit-switch endpoint, follow these steps to complete the integration:

Step 1: Initialize the Atomic Transact SDK

Use the public_token received from Upwardli to initialize the Atomic Transact SDK. This will create a session and validate the token.

Important: Configuration Differences

Bill Switch requires:

  • scope: "pay-link"
  • tasks: [{ operation: "switch" }]

Direct Deposit Switch requires:

  • scope: "user-link"
  • tasks: [{ operation: "deposit" }]

Bill Switch - Web Implementation Example:

1import { Atomic } from '@atomicfi/transact';
2
3// Use the token from Upwardli's bill-switch endpoint
4const publicToken = 'YOUR_PUBLIC_TOKEN_FROM_UPWARDLI';
5
6Atomic.transact({
7 config: {
8 publicToken: publicToken,
9 scope: 'pay-link', // Required for Bill Switch
10 tasks: [{ operation: 'switch' }], // Required for Bill Switch
11 theme: {
12 brandColor: '#9460FE',
13 dark: false
14 },
15 language: 'en'
16 },
17 onAuthStatusUpdate: (status) => {
18 console.log('Authentication status:', status.status);
19 },
20 onTaskStatusUpdate: (task) => {
21 console.log('Task status update:', task.taskId, task.status);
22 },
23 onError: (error) => {
24 console.error('Atomic SDK error:', error);
25 },
26 onFinish: (data) => {
27 console.log('Task completed:', data.taskId);
28 }
29});

Direct Deposit Switch - Web Implementation Example:

1import { Atomic } from '@atomicfi/transact';
2
3// Use the token from Upwardli's deposit-switch endpoint
4const publicToken = 'YOUR_PUBLIC_TOKEN_FROM_UPWARDLI';
5
6Atomic.transact({
7 config: {
8 publicToken: publicToken,
9 scope: 'user-link', // Required for Direct Deposit Switch
10 tasks: [{ operation: 'deposit' }], // Required for Direct Deposit Switch
11 theme: {
12 brandColor: '#9460FE',
13 dark: false
14 },
15 language: 'en'
16 },
17 onAuthStatusUpdate: (status) => {
18 console.log('Authentication status:', status.status);
19 },
20 onTaskStatusUpdate: (task) => {
21 console.log('Task status update:', task.taskId, task.status);
22 },
23 onError: (error) => {
24 console.error('Atomic SDK error:', error);
25 },
26 onFinish: (data) => {
27 console.log('Task completed:', data.taskId);
28 }
29});

Bill Switch - React Native Example:

1import { Atomic } from "@atomicfi/transact-react-native";
2
3const publicToken = 'YOUR_PUBLIC_TOKEN_FROM_UPWARDLI';
4
5Atomic.transact({
6 config: {
7 scope: "pay-link", // Required for Bill Switch
8 publicToken: publicToken,
9 tasks: [{ operation: "switch" }], // Required for Bill Switch
10 theme: {
11 brandColor: "#9460FE",
12 dark: false
13 },
14 language: "en"
15 },
16 onAuthStatusUpdate: status => {
17 console.log('Auth status:', status.status);
18 },
19 onTaskStatusUpdate: task => {
20 console.log('Task', task.taskId, 'status:', task.status);
21 },
22 onError: error => {
23 console.log('Error:', error);
24 }
25});

Direct Deposit Switch - React Native Example:

1import { Atomic } from "@atomicfi/transact-react-native";
2
3const publicToken = 'YOUR_PUBLIC_TOKEN_FROM_UPWARDLI';
4
5Atomic.transact({
6 config: {
7 scope: "user-link", // Required for Direct Deposit Switch
8 publicToken: publicToken,
9 tasks: [{ operation: "deposit" }], // Required for Direct Deposit Switch
10 theme: {
11 brandColor: "#9460FE",
12 dark: false
13 },
14 language: "en"
15 },
16 onAuthStatusUpdate: status => {
17 console.log('Auth status:', status.status);
18 },
19 onTaskStatusUpdate: task => {
20 console.log('Task', task.taskId, 'status:', task.status);
21 },
22 onError: error => {
23 console.log('Error:', error);
24 }
25});

Step 2: Verify Token Validity

When the SDK initializes, it will automatically validate the token. Monitor the onError callback to catch any token validation errors:

1onError: (error) => {
2 if (error.message.includes('invalid token') || error.message.includes('expired')) {
3 console.error('Token validation failed:', error);
4 // Request a new token from Upwardli's endpoint
5 }
6}

Step 3: Handle Payment Card Data Request

Atomic will request the payment card details through the onDataRequest callback. You need to ensure your implementation can provide this data when requested.

Important: You must specify the deferredPaymentMethodStrategy parameter as either 'sdk' or 'api' depending on how you want to provide the card data.

SDK Strategy Example:

1import { Atomic } from '@atomicfi/transact';
2
3Atomic.transact({
4 config: {
5 publicToken: publicToken,
6 scope: 'pay-link',
7 tasks: [{ operation: 'switch' }],
8 deferredPaymentMethodStrategy: 'sdk', // Specify SDK strategy
9 theme: {
10 brandColor: '#9460FE',
11 dark: false
12 }
13 },
14 onDataRequest: (request) => {
15 console.log('Data request received:', request.fields);
16
17 // The request.fields array will contain entities needed
18 // Possible values: ['account', 'card', 'identity']
19
20 if (request.fields.includes('card')) {
21 // Return card data through the SDK
22 const cardData = {
23 number: '4111111111111111',
24 expiry: '03/29',
25 cvv: '111'
26 };
27
28 const identity = {
29 firstName: 'John',
30 lastName: 'Doe',
31 postalCode: '12345',
32 address: '123 Main St',
33 city: 'New York',
34 state: 'NY',
35 phone: '5551234567',
36 email: 'john.doe@example.com'
37 };
38
39 return { card: cardData, identity: identity };
40 }
41 }
42});

API Strategy Example:

If you prefer to send card data via the Atomic API instead of through the SDK:

1onDataRequest: async (request) => {
2 console.log('Data request received:', request);
3
4 // Send card data to Atomic's Update User endpoint
5 if (request.fields.includes('card')) {
6 await fetch('https://api.atomicfi.com/user', {
7 method: 'PATCH',
8 headers: {
9 'Content-Type': 'application/json',
10 'x-api-key': 'YOUR_ATOMIC_API_KEY',
11 'x-api-secret': 'YOUR_ATOMIC_API_SECRET'
12 },
13 body: JSON.stringify({
14 identifier: request.identifier,
15 card: {
16 number: '4111111111111111',
17 expiry: '03/29',
18 cvv: '111'
19 }
20 })
21 });
22 }
23}

Step 4: Confirm Event Delivery

Atomic will send webhook events for transaction updates. Ensure your webhook endpoint is configured to receive these events.

Key Events to Monitor:

  1. task-status-update - Fired when a task status changes (processing, completed, failed)
  2. auth-status-update - Fired when authentication status changes
  3. task-completed - Fired when a switch task completes successfully
  4. task-failed - Fired when a task fails

Webhook Configuration:

Configure your webhook endpoint in the Atomic Console. Your endpoint should accept POST requests with the following structure:

1{
2 "event": "task-status-update",
3 "data": {
4 "taskId": "abc123",
5 "userId": "user_xyz",
6 "product": "switch",
7 "status": "completed",
8 "company": {
9 "_id": "company_123",
10 "name": "Example Payroll"
11 },
12 "switchData": {
13 "paymentMethod": {
14 "type": "card",
15 "brand": "Visa",
16 "lastFour": "1111",
17 "expiry": "03/29"
18 }
19 }
20 }
21}

Example Webhook Handler:

1app.post('/webhooks/atomic', (req, res) => {
2 const { event, data } = req.body;
3
4 console.log('Received Atomic webhook:', event);
5
6 switch(event) {
7 case 'task-status-update':
8 console.log(`Task ${data.taskId} status: ${data.status}`);
9 if (data.status === 'completed') {
10 // Handle successful switch
11 console.log('Switch completed for company:', data.company.name);
12 } else if (data.status === 'failed') {
13 // Handle failed switch
14 console.log('Switch failed:', data.failReason);
15 }
16 break;
17
18 case 'auth-status-update':
19 console.log('User authenticated with:', data.company.name);
20 break;
21
22 default:
23 console.log('Unhandled event type:', event);
24 }
25
26 // Always respond with 200 to acknowledge receipt
27 res.status(200).send('OK');
28});

Testing Your Integration

Atomic provides test credentials to simulate various scenarios. You can use these in development:

Successful Flow:

  • Username: test-good
  • Password: Any password
  • Description: Tests a successful operation

MFA Flow:

  • Username: test-code-mfa
  • Password: Any password
  • Description: Tests authentication with device code MFA

Failure Scenarios:

  • Username: test-bad - Tests unsuccessful authentication
  • Username: test-system-unavailable - Tests third-party system outage
  • Username: test-failure - Tests post-authentication failure

For a complete list of test credentials and scenarios, refer to the Atomic SDK Testing Documentation.


Complete Integration Checklist

  • Request token from Upwardli’s /bill-switch/token or /deposit-switch/token endpoint
  • Initialize Atomic Transact SDK with the received public_token
  • Verify token validity through error callbacks
  • Implement onDataRequest callback to provide card details via SDK or API
  • Configure webhook endpoint in Atomic Console
  • Verify webhook events are being received for task status updates
  • Test with Atomic’s test credentials
  • Handle error scenarios appropriately

Additional Resources