Introduction

The sandbox environment functions as a simulated version of the actual system, designed for testing and development purposes without interacting with real data.

This environment employs mock payroll providers and payslip readers in order to allow developers to evaluate the API interface without compromising real data privacy.

Setting Up for Testing

Before you begin testing, ensure you have the following:

  • An API key for authentication: please ask your Teal connection to supply you with an API key
  • A callback URL for receiving webhook notifications: generate your URL in webhook.site

1. Webhooks Setup /webhooks

Configure webhooks to receive notifications for events such as new payroll submissions.

curl --request POST \
  --url https://api.sandbox.goteal.co/webhooks \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '{
  "events": [
    "user-payroll-submitted",
    "user-payroll-created"
  ],
  "name": "user-payroll-submitted",
  "secret": "very-secret",
  "url": "https://webhooks.company.com"
}'

Response Example:

{
  "webhook_id": "95a0e70b-fe02-4f47-aef9-2efff279df71",
  "events": [
    "user-payroll-submitted",
    "user-payroll-created"
  ],
  "name": "user-payroll-submitted",
  "url": "https://webhooks.company.com",
  "created_at": "2019-05-17T00:00:00.000Z"
}

2. Create a user /users

Now you need to create a user selecting a user ID from the following users:

curl --request POST \
  --url https://api.sandbox.goteal.co/users \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '{
  "name": "John Smith",
  "email": "john.smith@company.com"
}'

The field email does not have to be a real email address. It can be the user’s identifier in your system.

Response Example:

{
  "user_id": "95a0e70b-fe02-4f47-aef9-2efff279df71",
  "name": "John Smith",
  "email": "john.smith@company.com",
  "created_at": "2019-05-17T00:00:00.000Z"
}

3. Generating a user token /user-tokens

After creating a webhook, generate a token to authenticate subsequent actions for that user. The token ensures that actions such as account connection and payslip uploads are securely attributed to the correct user.

curl --request POST \
  --url https://api.sandbox.goteal.co/user-tokens \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '{
  "user_id": "95a0e70b-fe02-4f47-aef9-2efff279df71"
}'

Response Example:

{
  "created_at": "2019-05-17T00:00:00.000Z",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTVhMGU3MGItZmUwMi00ZjQ3LWFlZjktMmVmZmYyNzlkZjcxIiwiaWF0IjoxNTE2MjM5MDIyfQ.4S5J"
}

4. Connecting a Payroll Account /accounts

This simulates the user connecting their payroll account for automatic data retrieval.

curl --request POST \
  --url https://api.sandbox.goteal.co/accounts \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '{
  "user_id": "95a0e70b-fe02-4f47-aef9-2efff279df71",
  "password": "very-secret-password",
  "payroll_provider": "quickbooks",
  "user_name": "john.smith@company.com"
}'

Response Example:

{
  "account_id": "95a0e70b-fe02-4f47-aef9-2efff279df71",
  "created_at": "2019-05-17T00:00:00.000Z",
  "payroll_provider": "quickbooks",
  "user_name": "john.smith@company.com"
}

5. Retrieve submitted Payroll information /entries/connections

Retrieve payroll for a connected account.

curl --location --request POST 'https://api.sandbox.goteal.co/entries/connections' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfbmFtZSI6InN5c19jbGllbnQxIiwidXNlcl9pZCI6IjU3YWRiMzg0LWE2ZGEtNGE1Ny05NThhLTU1ZDk5MzdjZWE0MyIsImlzcyI6ImFwcC5zYW5kYm94LmdvdGVhbC5jbyIsImV4cCI6MTcxNTM0NTI5MH0.IxgmSN4XAn7j2jbQu0npwLXQjEQVqcbjmIBO2T-NCAc' \
--header 'Content-Type: application/json' \
--data-raw '{
    "account_id" : 552300dd-1e91-48d4-958b-41736c2c0167
}'

Response Example:

{
    "account_id": "552300dd-1e91-48d4-958b-41736c2c0167",
    "entry_id": "bdc420fe-5e48-4802-a753-659979a2a346",
    "payroll_submissions": [
        {
            "id": "0187c66e-e7e5-811c-b006-2232f00f426a",
            "account_id": "552300dd-1e91-48d4-958b-41736c2c0167",
            "entry_id": "bdc420fe-5e48-4802-a753-659979a2a346",
            "created_at": "2024-05-03T14:00:13.804Z",
            "identity_information": {
                "name": "Jane Doe",
                "date_of_birth": "1990-04-01",
                "address": {
                    "street": "123 Main St",
                    "county": "Anyshire",
                    "city": "Anycity",
                    "post_code": "AB12 3CD",
                    "country": "Countryland"
                },
                "email": "jane.doe@example.com",
                "phone": "+1234567890",
                "NI_number": "AB123456C"
            },
            "employment_information": {
                "employer_name": "Acme Corp",
                "role": "Software Developer",
                "type": "Full-Time",
                "status": "Active",
                "start_date": "2018-06-01",
                "leave_date": null
            },
            "income_information": {
                "pay_date": "2024-02-15",
                "pay_interval_start": "2024-02-01",
                "pay_interval_end": "2024-02-15",
                "pay_frequency": "weekly",
                "earnings": {
                    "gross_pay": 2000,
                    "net_pay": 1500,
                    "base_salary": 1900,
                    "bonus": 100
                },
                "deductions": {
                    "income_tax": 300,
                    "employee_ni": 150,
                    "employee_pension": 50,
                    "total_deductions": 500
                }
            }
        },
        {
            "id": "0187c66e-e7e5-811c-b006-2232f00f426a",
            "account_id": "552300dd-1e91-48d4-958b-41736c2c0167",
            "entry_id": "bdc420fe-5e48-4802-a753-659979a2a346",
            "created_at": "2024-05-03T14:00:13.804Z",
            "identity_information": {
                "name": "Jane Doe",
                "date_of_birth": "1990-04-01",
                "address": {
                    "street": "123 Main St",
                    "county": "Anyshire",
                    "city": "Anycity",
                    "post_code": "AB12 3CD",
                    "country": "Countryland"
                },
                "email": "jane.doe@example.com",
                "phone": "+1234567890",
                "NI_number": "AB123456C"
            },
            "employment_information": {
                "employer_name": "Acme Corp",
                "role": "Software Developer",
                "type": "Full-Time",
                "status": "Active",
                "start_date": "2018-06-01",
                "leave_date": null
            },
            "income_information": {
                "pay_date": "2024-02-15",
                "pay_interval_start": "2024-02-01",
                "pay_interval_end": "2024-02-15",
                "pay_frequency": "weekly",
                "earnings": {
                    "gross_pay": 2000,
                    "net_pay": 1500,
                    "base_salary": 1900,
                    "bonus": 100
                },
                "deductions": {
                    "income_tax": 300,
                    "employee_ni": 150,
                    "employee_pension": 50,
                    "total_deductions": 500
                }
            }
        },
        {
            "id": "0187c66e-e7e5-811c-b006-2232f00f426a",
            "account_id": "552300dd-1e91-48d4-958b-41736c2c0167",
            "entry_id": "bdc420fe-5e48-4802-a753-659979a2a346",
            "created_at": "2024-05-03T14:00:13.804Z",
            "identity_information": {
                "name": "Jane Doe",
                "date_of_birth": "1990-04-01",
                "address": {
                    "street": "123 Main St",
                    "county": "Anyshire",
                    "city": "Anycity",
                    "post_code": "AB12 3CD",
                    "country": "Countryland"
                },
                "email": "jane.doe@example.com",
                "phone": "+1234567890",
                "NI_number": "AB123456C"
            },
            "employment_information": {
                "employer_name": "Acme Corp",
                "role": "Software Developer",
                "type": "Full-Time",
                "status": "Active",
                "start_date": "2018-06-01",
                "leave_date": null
            },
            "income_information": {
                "pay_date": "2024-02-15",
                "pay_interval_start": "2024-02-01",
                "pay_interval_end": "2024-02-15",
                "pay_frequency": "weekly",
                "earnings": {
                    "gross_pay": 2000,
                    "net_pay": 1500,
                    "base_salary": 1900,
                    "bonus": 100
                },
                "deductions": {
                    "income_tax": 300,
                    "employee_ni": 150,
                    "employee_pension": 50,
                    "total_deductions": 500
                }
            }
        }
    ]
}

6. Extract Payroll information from a payslip /entries/payslips

This request simulates the user uploading a payslip to extract payroll information. Extracting payslip information can be done using the endpoint below but will usually be done by the user through the WebApp as per section 8

curl --location --request POST 'https://api.sandbox.goteal.co/entries/payslips' \
--header 'Authorization: Bearer <bearer-token>' \
--form 'file=@"<path-to-file>"'

Response Example:

{
    "account_id": "95a0e70b-fe02-4f47-aef9-2efff279df71",
    "entry_id": "f5e0a310-d4d0-4db0-b5c3-895a81e26e03",
    "payroll_submissions": [
        {
            "id": "0187c66e-e7e5-811c-b006-2232f00f426a",
            "account_id": null,
            "entry_id": "f5e0a310-d4d0-4db0-b5c3-895a81e26e03",
            "created_at": "2024-05-03T12:48:54.886Z",
            "identity_information": {
                "name": "Jane Doe",
                "date_of_birth": "1990-04-01",
                "address": {
                    "street": "123 Main St",
                    "county": "Anyshire",
                    "city": "Anycity",
                    "post_code": "AB12 3CD",
                    "country": "Countryland"
                },
                "email": "jane.doe@example.com",
                "phone": "+1234567890",
                "NI_number": "AB123456C",
                "employment_information": {
                    "employer_name": "Acme Corp",
                    "role": "Software Developer",
                    "type": "Full-Time",
                    "status": "Active",
                    "start_date": "2018-06-01",
                    "leave_date": null
                },
                "income_information": {
                    "pay_date": "2024-02-15",
                    "pay_interval_start": "2024-02-01",
                    "pay_interval_end": "2024-02-15",
                    "pay_frequency": "weekly",
                    "earnings": {
                        "gross_pay": 2000,
                        "net_pay": 1500,
                        "base_salary": 1900,
                        "bonus": 100
                    },
                    "deductions": {
                        "income_tax": 300,
                        "employee_ni": 150,
                        "employee_pension": 50,
                        "total_deductions": 500
                    }
                }
            }
        }
    ]
}

7. Retrieving Payroll Data /payroll

Retrieve the payroll data submitted through the connected account or document upload.

curl --request GET \
  --url https://api.sandbox.goteal.co/payroll/{user_id} \
  --header 'X-API-KEY: <api-key>'

Response Example:

{
  "pagination": {
    "count": 14,
    "limit": 25,
    "offset": 75,
    "total_count": 89
  },
  "payroll_submissions": [
    {
      "id": "95a0e70b-fe02-4f47-aef9-2efff279df71",
      "account_id": "0988b4bd-42dd-4556-95ae-27a906c066ec",
      "entry_id": "0d2bcb9b-a7ec-463f-bd7e-aacaa1a190a4",
      "created_at": "2019-05-17T00:00:00.000Z",
      "document_external_id": null,
      "document_filename": null,
      "employment_information": {
        "employer_name": "Acme Ltd",
        "leave_date": "2019-05-17T00:00:00.000Z",
        "role": "Software Engineer",
        "start_date": "2019-05-17T00:00:00.000Z",
        "status": "Active",
        "type": "Full-time"
      },
      "identity_information": {
        "NI_number": "AB123456C",
        "address": {
          "city": "London",
          "country": "United Kingdom",
          "county": "Greater London",
          "post_code": "SW1A 1AA",
          "street": "123 Main Street"
        },
        "date_of_birth": "2019-05-17T00:00:00.000Z",
        "email": "john.smith@company.com",
        "name": "John Smith",
        "phone": 447123456789
      },
      "income_information": {
        "deductions": {
          "employee_ni": 200,
          "employee_pension": 300,
          "income_tax": 500,
          "total_deductions": 1000
        },
        "earnings": {
          "base_salary": 3000,
          "bonus": 500,
          "gross_pay": 3500,
          "net_pay": 2500
        },
        "pay_date": "2019-05-17T00:00:00.000Z",
        "pay_frequency": "Monthly",
        "pay_interval_end": "2019-05-17T00:00:00.000Z",
        "pay_interval_start": "2019-05-17T00:00:00.000Z"
      }
    }
  ]
}

8. WebApp usage

Teal’s webapp can be tested by accessing https://app.sandbox.goteal.co/ in the browser. Use the generated bearer token in order to identify the user https://app.sandbox.goteal.co/?jwt=<bearer-token>. The webapp uses the same API mechanism as the mentioned above, therefore the data will be retrieved in the same way.

Connect a Payroll:

Submit a Payroll:

9. Cleanup: Deleting a User /users

After testing, clean up by deleting the test user and their associated data.

curl --request DELETE \
  --url https://api.sandbox.goteal.co/users/{user_id} \
  --header 'X-API-KEY: <api-key>'

Response Example:

{
  "message": "User deleted successfully."
}