TOS Acceptance
Collect Terms of Service and Privacy Policy acceptance from your users.
Overview
Before an account can transact, the user must accept Due's Terms of Service (TOS) and Privacy Policy. There are two ways to handle this:
- Due-hosted - Redirect the user to a Due-hosted acceptance page using the
linkfield. Due handles presenting the documents and collecting acceptance. This is the simplest integration. - Manual - Present the documents yourself using the
documentLinks, collect the user's real IP address, and submit their acceptance via the API.
Both flows start the same way: create an account and extract the tos object from the response.
Step 1 - Create an Account
Create an account via Create account. The response includes a tos object:
{
"id": "acct_...",
// ...
"tos": {
"id": "ta_...",
"entityName": "DUE LTD",
"status": "pending",
"link": "/tos/token_1234567890",
"documentLinks": {
"tos": "https://link.to/terms_of_service",
"privacyPolicy": "https://link.to/privacy_policy"
},
"acceptedAt": null,
"token": "token_1234567890"
}
}TOS Object Fields:
| Field | Type | Description |
|---|---|---|
status | string | Current TOS status. Either pending or accepted. |
link | string | Relative URL to the Due-hosted TOS acceptance page. Use this for the hosted flow. |
documentLinks.tos | string | URL to the Terms of Service PDF. |
documentLinks.privacyPolicy | string | URL to the Privacy Policy PDF. |
token | string | One-time token used as the path parameter in the manual acceptance request. |
entityName | string | Name of the legal entity issuing the terms. |
acceptedAt | string | null | ISO 8601 timestamp of acceptance, or null if pending. |
Option A - Due-Hosted Acceptance
The simplest integration. Redirect the user to the Due-hosted acceptance page using the link field from the tos object:
https://app.due.network.network/tos/token_1234567890
Due handles everything: presenting the TOS and Privacy Policy documents, collecting the user's IP address, and recording the acceptance.
Once the user accepts, the tos.status on the account transitions to accepted.
Option B - Manual Acceptance
If you need full control over the user experience, you can handle TOS acceptance in your own UI.
Step 2 - Present the Documents
Display the TOS and Privacy Policy to the user using the URLs from documentLinks. These are publicly accessible S3 links to PDF documents.
Both documents must be presented before collecting acceptance:
- Terms of Service -
documentLinks.tos - Privacy Policy -
documentLinks.privacyPolicy
The specific legal entity and document versions are determined by the user's country at account creation time.
Step 3 - Collect the Client IP Address
Important: Real Client IP Required
The
ipAddressparameter must contain the actual client's IP address, not the IP of any intermediate proxy, load balancer, or server.If your application sits behind a proxy or load balancer, you need to extract the real client IP from headers such as
X-Forwarded-For,X-Real-IP, or similar, depending on your infrastructure configuration.
Step 4 - Submit TOS Acceptance
Request
POST /v1/tos/{token}
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
token | string | Yes | The TOS token from Step 1. |
Headers:
| Header | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer token. |
Body:
{
"ipAddress": "203.0.113.42"
}| Field | Type | Required | Description |
|---|---|---|---|
ipAddress | string | Yes | The real IP address of the user accepting the terms. |
Response
{
"id": "ta_...",
"entityName": "DUE LTD",
"status": "accepted",
"link": "/tos/token_1234567890",
"documentLinks": {
"tos": "https://link.to/terms_of_service",
"privacyPolicy": "https://link.to/privacy_policy"
},
"acceptedAt": "2026-02-04T22:26:24.30097021Z",
"token": "token_1234567890"
}Retrieving TOS Data
You can retrieve the current TOS state at any time:
GET /v1/tos/{token}
Returns the same TOS acceptance object shown above.
Webhook Events
When TOS is accepted, a tos_accepted webhook event is dispatched containing the full account object:
{
"id": "evt_...",
"type": "bp.tos_accepted",
"data": {
"id": "acct_...",
"type": "individual",
"name": "John Snow",
"email": "[email protected]",
"country": "US",
"category": "self-employed",
"status": "passed",
"kyc": {
"status": "passed",
"link": "http://link.to/kyc",
},
"tos": {
"id": "ta_...",
"entityName": "DUE LTD",
"status": "accepted",
"link": "/tos/token_1234567890",
"documentLinks": {
"tos": "https://link.to/terms_of_service",
"privacyPolicy": "https://link.to/privacy_policy"
},
"acceptedAt": "2026-02-04T22:26:24.30097021Z",
"token": "token_1234567890"
}
},
"occurredAt": "2026-02-04T22:28:35.398380671Z",
"attemptedAt": "2026-02-04T22:28:35.40067069Z"
}Example integration
# Step 1 - Fetch account to get TOS data
ACCOUNT=$(curl -s -X GET "https://api.due.network/v1/accounts/ACCOUNT_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json")
TOKEN=$(echo "$ACCOUNT" | jq -r ".tos.token")
echo "TOS: $(echo "$ACCOUNT" | jq -r ".tos.documentLinks.tos")"
echo "Privacy Policy: $(echo "$ACCOUNT" | jq -r ".tos.documentLinks.privacyPolicy")"
# Step 2 - Present the document links to the user
# Step 3 - Submit TOS acceptance with the user's real IP
curl -X POST "https://api.due.network/v1/tos/$TOKEN" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ipAddress": "203.0.113.42"}'
import requests
API_BASE = "https://api.due.network"
API_KEY = "YOUR_API_KEY"
def accept_tos(account_id: str, client_ip: str) -> dict:
# Step 1 - Fetch account to get TOS data
account = requests.get(
f"{API_BASE}/v1/accounts/{account_id}",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
)
account.raise_for_status()
account = account.json()
tos = account["tos"]
token = tos["token"]
# Step 2 - Present documents to user
tos_url = tos["documentLinks"]["tos"]
privacy_url = tos["documentLinks"]["privacyPolicy"]
# Display these PDFs to the user in your UI
# Step 3 - Submit TOS acceptance with the user's real IP
response = requests.post(
f"{API_BASE}/v1/tos/{token}",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={
"ipAddress": client_ip
}
)
response.raise_for_status()
result = response.json()
if result["status"] == "accepted":
return {
"status": "accepted",
"acceptedAt": result["acceptedAt"]
}
return {"status": "pending"}
Updated 15 days ago