curl --request POST \
--url https://api.platform.dakota.xyz/applications/{application_id}/attestations \
--header 'Content-Type: application/json' \
--header 'X-Application-Token: <api-key>' \
--header 'x-idempotency-key: <x-idempotency-key>' \
--data '
{
"attestation_type": "information_accuracy",
"timestamp": 1705315800,
"applicant_id": "2hCjxJzUAW6JVRkZqaF9E0KpM3b"
}
'const options = {
method: 'POST',
headers: {
'x-idempotency-key': '<x-idempotency-key>',
'X-Application-Token': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
attestation_type: 'information_accuracy',
timestamp: 1705315800,
applicant_id: '2hCjxJzUAW6JVRkZqaF9E0KpM3b'
})
};
fetch('https://api.platform.dakota.xyz/applications/{application_id}/attestations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.platform.dakota.xyz/applications/{application_id}/attestations"
payload = {
"attestation_type": "information_accuracy",
"timestamp": 1705315800,
"applicant_id": "2hCjxJzUAW6JVRkZqaF9E0KpM3b"
}
headers = {
"x-idempotency-key": "<x-idempotency-key>",
"X-Application-Token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.dakota.xyz/applications/{application_id}/attestations"
payload := strings.NewReader("{\n \"attestation_type\": \"information_accuracy\",\n \"timestamp\": 1705315800,\n \"applicant_id\": \"2hCjxJzUAW6JVRkZqaF9E0KpM3b\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-idempotency-key", "<x-idempotency-key>")
req.Header.Add("X-Application-Token", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Submit an attestation for an application
Submits an attestation for an application. For business applications, the attestor must be a control person. For individual applications, the attestor must be the individual.
The attestor is identified by applicant_id; the request carries no name. The applicantās
name is stored on the attestation when it is accepted; attested_by in responses shows
that recorded name, so renaming the applicant later does not change it. Only an
attestation with no recorded name falls back to the applicantās current name, and then to
Unknown if the applicant is no longer on the application.
If the applicantās name changes after they attest, the applicationās attestation validation reports the mismatch. Submitting the application while the mismatch stands is refused with 400 and deletes all of that applicantās attestations, so the same applicant must then submit them again.
Ordering. Submit e_sign first, and wait for that request to succeed before sending any
other attestation. Every other attestation type must carry a timestamp strictly later than
the applicationās earliest e_sign attestation, otherwise the request is rejected with 400
(Attestation timestamp must be after e-sign attestation timestamp). Timestamps are whole
Unix seconds, so an attestation stamped in the same second as e_sign is rejected too: stamp
e_sign at a time T and every other type at T + 1 or later.
A partner disclosure acceptance (a request with disclosure_id) is not refused on this
ground, but the applicationās attestation validation applies the same rule to it: a
disclosure stamped at or before e_sign is accepted with 204 and then blocks submission.
Stamp disclosure acceptances after e_sign too.
Timestamp range. timestamp must be on or after 2024-01-01T00:00:00Z and no more than
24 hours in the future. An acceptance of a specific document revision is also rejected when
its timestamp is more than 24 hours before that revision went live.
Authentication: Accepts Application Token (X-Application-Token header).
curl --request POST \
--url https://api.platform.dakota.xyz/applications/{application_id}/attestations \
--header 'Content-Type: application/json' \
--header 'X-Application-Token: <api-key>' \
--header 'x-idempotency-key: <x-idempotency-key>' \
--data '
{
"attestation_type": "information_accuracy",
"timestamp": 1705315800,
"applicant_id": "2hCjxJzUAW6JVRkZqaF9E0KpM3b"
}
'const options = {
method: 'POST',
headers: {
'x-idempotency-key': '<x-idempotency-key>',
'X-Application-Token': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
attestation_type: 'information_accuracy',
timestamp: 1705315800,
applicant_id: '2hCjxJzUAW6JVRkZqaF9E0KpM3b'
})
};
fetch('https://api.platform.dakota.xyz/applications/{application_id}/attestations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.platform.dakota.xyz/applications/{application_id}/attestations"
payload = {
"attestation_type": "information_accuracy",
"timestamp": 1705315800,
"applicant_id": "2hCjxJzUAW6JVRkZqaF9E0KpM3b"
}
headers = {
"x-idempotency-key": "<x-idempotency-key>",
"X-Application-Token": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.platform.dakota.xyz/applications/{application_id}/attestations"
payload := strings.NewReader("{\n \"attestation_type\": \"information_accuracy\",\n \"timestamp\": 1705315800,\n \"applicant_id\": \"2hCjxJzUAW6JVRkZqaF9E0KpM3b\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-idempotency-key", "<x-idempotency-key>")
req.Header.Add("X-Application-Token", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}Authorizations
Application-specific token for public URL access. Generated when a customer is created. Provides access to a single application without requiring an API key. Token is valid for 90 days and rate-limited to 250 requests per hour.
Headers
Unique key (UUID) to ensure request idempotency on POST, PUT and PATCH requests.
A key is scoped to your client, the HTTP method and the path, and is remembered for 24 hours after a
successful (below 400) response. Repeating the same request (same JSON body, whatever the key order or
whitespace) with the same key within that window returns the original response with
X-Idempotent-Replayed: true instead of executing the request again. Using the same key on the same
endpoint with a different body returns 422 with problem type idempotency-key-reused; the request is
not executed. Error responses (4xx and 5xx) are not remembered, so a request refused for a fixable reason
can be corrected and retried under the same key. Request bodies that are not JSON (for example file
uploads) are not compared.
Path Parameters
The unique identifier for the application KSUID is a 27-character globally unique ID that combines a timestamp with a random component. Used for all entity identifiers in the Dakota platform.
27^[0-9A-Za-z]{27}$"1NFHrqBHb3cTfLVkFSGmHZqdDPi"
Body
Attestation submission data
Request to submit an attestation for a KYB application.
To accept a banking partner's disclosure online (the customer-facing
half of the partner-onboarding disclosure gate), additionally supply
disclosure_id (the terms key the provider declared, e.g.
partner_disclosures) and disclosure_version. When those fields are
present the attestation is recorded as a partner disclosure
acknowledgment with acceptance_channel = customer_online (acceptor
name + client IP captured server-side), advancing the partner-onboarding
substatus and ā for an already-approved application ā triggering the
programmatic reprovision. The API is partner-agnostic: callers supply a
terms key + version, never a partner name. When disclosure_id is
absent the behavior is a standard onboarding attestation.
Type of attestation being submitted
information_accuracy, terms_of_service, privacy_policy, funds_transfer_agreement, lead_bank_privacy_policy, e_sign "information_accuracy"
Unix epoch timestamp (in seconds) when the attestation was made. For every type other
than e_sign it must be strictly later than the application's earliest e_sign
timestamp, so a type stamped in the same second as e_sign is rejected. See
POST /applications/{application_id}/attestations for the ordering rule.
1705315800
ID of the individual applicant making the attestation. This is what identifies the attestor: the request carries no name, and the name recorded on the attestation is the one on this applicant's record.
"2hCjxJzUAW6JVRkZqaF9E0KpM3b"
Optional. The partner disclosure terms key the customer is
accepting, as declared by the provider (e.g. partner_disclosures).
When present, this attestation is recorded as a partner disclosure
acknowledgment. Partner-agnostic ā a terms key, never a partner name.
While the application is still in onboarding, an acceptance recorded this way needs the e-sign acceptance to exist already and its timestamp to be after the e-sign acceptance's; otherwise the request is refused with a 400.
"partner_disclosures"
Optional. The version of the partner disclosure being accepted
(e.g. 2026-06). Required when disclosure_id is present.
"2026-06"
Optional. The version of the Dakota-published document the customer
was actually shown, as returned by
GET /legal/documents/{document_key}.
Pass it whenever you render the text yourself. Without it the acceptance is pinned to whichever revision is in force when the request arrives ā which is not necessarily the one on the customer's screen, if a new revision went live between render and submit. Rejected with 400 if that version is not currently in force, so a stale page fails loudly instead of recording consent to text nobody read.
Ignored when disclosure_id is present; use disclosure_version
for partner disclosures.
"2026-07-23"
Response
Attestation submitted successfully
Was this page helpful?

