curl --request POST \
--url https://api.sandbox.goteal.co/payroll/entries/payslips/presign \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"files": [
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"}
]
}'
import json
import requests
token = "<token>"
url = "https://api.sandbox.goteal.co/payroll/entries/payslips/presign"
payload = {
"files": [
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"},
]
}
response = requests.post(
url,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
json=payload,
)
response.raise_for_status()
print(json.dumps(response.json(), indent=2))
import axios from 'axios'
const token = '<token>'
const response = await axios.post(
'https://api.sandbox.goteal.co/payroll/entries/payslips/presign',
{
files: [
{ file_name: 'payslip1.pdf', external_id: 'ext-jan-2024' },
{ file_name: 'payslip2.pdf' }
]
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
)
console.log(response.data)
<?php
$token = '<token>';
$payload = json_encode([
'files' => [
['file_name' => 'payslip1.pdf', 'external_id' => 'ext-jan-2024'],
['file_name' => 'payslip2.pdf'],
],
]);
$curl = curl_init('https://api.sandbox.goteal.co/payroll/entries/payslips/presign');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
],
]);
$response = curl_exec($curl);
if ($response === false) {
throw new RuntimeException('cURL error: ' . curl_error($curl));
}
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($statusCode >= 400) {
throw new RuntimeException('Request failed: ' . $response);
}
print_r(json_decode($response, true));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
payload := map[string]any{
"files": []map[string]any{
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"},
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(
"POST",
"https://api.sandbox.goteal.co/payroll/entries/payslips/presign",
bytes.NewBuffer(body),
)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
respBody, _ := io.ReadAll(resp.Body)
panic(fmt.Sprintf("request failed: %s", string(respBody)))
}
respBody, _ := io.ReadAll(resp.Body)
fmt.Println(string(respBody))
}
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
String token = "<token>";
HttpResponse<String> response = Unirest.post("https://api.sandbox.goteal.co/payroll/entries/payslips/presign")
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.body("{\n \"files\": [\n {\"file_name\": \"payslip1.pdf\", \"external_id\": \"ext-jan-2024\"},\n {\"file_name\": \"payslip2.pdf\"}\n ]\n}")
.asString();
if (!response.isSuccess()) {
throw new RuntimeException("Presign request failed: " + response.getBody());
}
System.out.println(response.getBody());
{
"presigned_urls": [
{
"file_name": "payslip1.pdf",
"external_id": "ext-jan-2024",
"presigned_url": "https://s3.amazonaws.com/bucket/presigned-uploads/payslip1.pdf?signature=abc123",
"path": "client/acct123/users/user456/payslip1.pdf"
},
{
"file_name": "payslip2.pdf",
"presigned_url": "https://s3.amazonaws.com/bucket/presigned-uploads/payslip2.pdf?signature=def456",
"path": "client/acct123/users/user456/payslip2.pdf"
}
]
}
Payroll
Generate presigned payslip URLs
Generates short-lived presigned URLs that you can use to upload payslip PDFs directly to Teal-managed storage. Use this endpoint before uploading any files and submitting them for processing.
POST
/
payroll
/
entries
/
payslips
/
presign
curl --request POST \
--url https://api.sandbox.goteal.co/payroll/entries/payslips/presign \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"files": [
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"}
]
}'
import json
import requests
token = "<token>"
url = "https://api.sandbox.goteal.co/payroll/entries/payslips/presign"
payload = {
"files": [
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"},
]
}
response = requests.post(
url,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
json=payload,
)
response.raise_for_status()
print(json.dumps(response.json(), indent=2))
import axios from 'axios'
const token = '<token>'
const response = await axios.post(
'https://api.sandbox.goteal.co/payroll/entries/payslips/presign',
{
files: [
{ file_name: 'payslip1.pdf', external_id: 'ext-jan-2024' },
{ file_name: 'payslip2.pdf' }
]
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
)
console.log(response.data)
<?php
$token = '<token>';
$payload = json_encode([
'files' => [
['file_name' => 'payslip1.pdf', 'external_id' => 'ext-jan-2024'],
['file_name' => 'payslip2.pdf'],
],
]);
$curl = curl_init('https://api.sandbox.goteal.co/payroll/entries/payslips/presign');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
],
]);
$response = curl_exec($curl);
if ($response === false) {
throw new RuntimeException('cURL error: ' . curl_error($curl));
}
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($statusCode >= 400) {
throw new RuntimeException('Request failed: ' . $response);
}
print_r(json_decode($response, true));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
payload := map[string]any{
"files": []map[string]any{
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"},
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(
"POST",
"https://api.sandbox.goteal.co/payroll/entries/payslips/presign",
bytes.NewBuffer(body),
)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
respBody, _ := io.ReadAll(resp.Body)
panic(fmt.Sprintf("request failed: %s", string(respBody)))
}
respBody, _ := io.ReadAll(resp.Body)
fmt.Println(string(respBody))
}
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
String token = "<token>";
HttpResponse<String> response = Unirest.post("https://api.sandbox.goteal.co/payroll/entries/payslips/presign")
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.body("{\n \"files\": [\n {\"file_name\": \"payslip1.pdf\", \"external_id\": \"ext-jan-2024\"},\n {\"file_name\": \"payslip2.pdf\"}\n ]\n}")
.asString();
if (!response.isSuccess()) {
throw new RuntimeException("Presign request failed: " + response.getBody());
}
System.out.println(response.getBody());
{
"presigned_urls": [
{
"file_name": "payslip1.pdf",
"external_id": "ext-jan-2024",
"presigned_url": "https://s3.amazonaws.com/bucket/presigned-uploads/payslip1.pdf?signature=abc123",
"path": "client/acct123/users/user456/payslip1.pdf"
},
{
"file_name": "payslip2.pdf",
"presigned_url": "https://s3.amazonaws.com/bucket/presigned-uploads/payslip2.pdf?signature=def456",
"path": "client/acct123/users/user456/payslip2.pdf"
}
]
}
This endpoint requires a valid authorisation for the user. If no active authorisation exists, the request will be rejected.
You can optionally pass the
x-teal-authorisation-id header to specify which authorisation to use; otherwise the system will resolve a valid authorisation automatically.
See Authorisations for more details.presigned_url values with HTTP PUT, then call
POST /payroll/entries/payslips to submit the uploaded documents for processing.
curl --request POST \
--url https://api.sandbox.goteal.co/payroll/entries/payslips/presign \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"files": [
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"}
]
}'
import json
import requests
token = "<token>"
url = "https://api.sandbox.goteal.co/payroll/entries/payslips/presign"
payload = {
"files": [
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"},
]
}
response = requests.post(
url,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
json=payload,
)
response.raise_for_status()
print(json.dumps(response.json(), indent=2))
import axios from 'axios'
const token = '<token>'
const response = await axios.post(
'https://api.sandbox.goteal.co/payroll/entries/payslips/presign',
{
files: [
{ file_name: 'payslip1.pdf', external_id: 'ext-jan-2024' },
{ file_name: 'payslip2.pdf' }
]
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
)
console.log(response.data)
<?php
$token = '<token>';
$payload = json_encode([
'files' => [
['file_name' => 'payslip1.pdf', 'external_id' => 'ext-jan-2024'],
['file_name' => 'payslip2.pdf'],
],
]);
$curl = curl_init('https://api.sandbox.goteal.co/payroll/entries/payslips/presign');
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
],
]);
$response = curl_exec($curl);
if ($response === false) {
throw new RuntimeException('cURL error: ' . curl_error($curl));
}
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($statusCode >= 400) {
throw new RuntimeException('Request failed: ' . $response);
}
print_r(json_decode($response, true));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
payload := map[string]any{
"files": []map[string]any{
{"file_name": "payslip1.pdf", "external_id": "ext-jan-2024"},
{"file_name": "payslip2.pdf"},
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(
"POST",
"https://api.sandbox.goteal.co/payroll/entries/payslips/presign",
bytes.NewBuffer(body),
)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
respBody, _ := io.ReadAll(resp.Body)
panic(fmt.Sprintf("request failed: %s", string(respBody)))
}
respBody, _ := io.ReadAll(resp.Body)
fmt.Println(string(respBody))
}
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
String token = "<token>";
HttpResponse<String> response = Unirest.post("https://api.sandbox.goteal.co/payroll/entries/payslips/presign")
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.body("{\n \"files\": [\n {\"file_name\": \"payslip1.pdf\", \"external_id\": \"ext-jan-2024\"},\n {\"file_name\": \"payslip2.pdf\"}\n ]\n}")
.asString();
if (!response.isSuccess()) {
throw new RuntimeException("Presign request failed: " + response.getBody());
}
System.out.println(response.getBody());
{
"presigned_urls": [
{
"file_name": "payslip1.pdf",
"external_id": "ext-jan-2024",
"presigned_url": "https://s3.amazonaws.com/bucket/presigned-uploads/payslip1.pdf?signature=abc123",
"path": "client/acct123/users/user456/payslip1.pdf"
},
{
"file_name": "payslip2.pdf",
"presigned_url": "https://s3.amazonaws.com/bucket/presigned-uploads/payslip2.pdf?signature=def456",
"path": "client/acct123/users/user456/payslip2.pdf"
}
]
}
Authorizations
Bearer token for authentication. The token should be the one returned by the /user-tokens endpoint.
Headers
Optional authorisation ID to associate with this request. If not provided, the system will attempt to resolve a valid authorisation for the user automatically.
Example:
"7f3b8c2a-1d4e-4f6a-8b8c-9a0b1c2d3e4f"
Body
application/json
Payslip files that require presigned upload URLs
Minimum array length:
1Show child attributes
Show child attributes
Response
Presigned URLs generated successfully
Generated URLs and metadata for uploading the requested files.
Show child attributes
Show child attributes
⌘I