curl -X POST "https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": null,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": true,
"last_four_ssn": "1234"
}'
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request['Authorization'] = 'Bearer YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
phone_number: '5551234567',
date_of_birth: '1990-01-15',
address_line_1: '123 Main Street',
address_line_2: nil,
city: 'San Francisco',
state: 'CA',
postal_code: '94102',
country: 'USA',
provider: 'plaid',
verified: true,
last_four_ssn: '1234'
}.to_json
response = http.request(request)
puts response.body
const axios = require('axios');
const upsertKyc = async () => {
try {
const response = await axios.post('https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert', {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
phone_number: '5551234567',
date_of_birth: '1990-01-15',
address_line_1: '123 Main Street',
address_line_2: null,
city: 'San Francisco',
state: 'CA',
postal_code: '94102',
country: 'USA',
provider: 'plaid',
verified: true,
last_four_ssn: '1234'
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
console.log(response.data);
} catch (error) {
console.error(error);
}
};
upsertKyc();
import requests
import json
url = "https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
data = {
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": None,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": True,
"last_four_ssn": "1234"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
{
"id": "id_A3GuXEbThpqk2t6UTxEuoceVJyUEAX7V",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": null,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": true
}
Upsert KYC
Submits a KYC identity record for a customer
curl -X POST "https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": null,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": true,
"last_four_ssn": "1234"
}'
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request['Authorization'] = 'Bearer YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
phone_number: '5551234567',
date_of_birth: '1990-01-15',
address_line_1: '123 Main Street',
address_line_2: nil,
city: 'San Francisco',
state: 'CA',
postal_code: '94102',
country: 'USA',
provider: 'plaid',
verified: true,
last_four_ssn: '1234'
}.to_json
response = http.request(request)
puts response.body
const axios = require('axios');
const upsertKyc = async () => {
try {
const response = await axios.post('https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert', {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
phone_number: '5551234567',
date_of_birth: '1990-01-15',
address_line_1: '123 Main Street',
address_line_2: null,
city: 'San Francisco',
state: 'CA',
postal_code: '94102',
country: 'USA',
provider: 'plaid',
verified: true,
last_four_ssn: '1234'
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
console.log(response.data);
} catch (error) {
console.error(error);
}
};
upsertKyc();
import requests
import json
url = "https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
data = {
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": None,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": True,
"last_four_ssn": "1234"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
{
"id": "id_A3GuXEbThpqk2t6UTxEuoceVJyUEAX7V",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": null,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": true
}
provider field identifies which KYC provider performed the verification. Accepted values are plaid, veriff, didit, sumsub, idology, seon, footprint, socure, geo_comply, acuity, surt, persona, and shufti.
Every Soap API request is authenticated with a bearer token in the Authorization header:
Authorization: Bearer YOUR_API_KEY
key_....
Requests with a missing or invalid API key return 422 — never 401 — with a JSON error field, usually {"error": "API key not found."}. Branch on the status code rather than the message: GET /api/v1/device_pings/latest_geo_check does not yet return the same wording.
Never expose your API key in client-side code — it is server-side only.
404 and the hint KYC upsert is disabled for this business. Contact Soap to enable it.How upserted records are used
- A customer can have several KYC records. Hosted checkout reads the most recent one, whether Soap created it during in-checkout verification or you submitted it here.
- Upserting
verified: falsefor a customer who already passed in-checkout verification therefore sends them back through verification on their next checkout that requires KYC. - In production, when KYC is enabled for a checkout type, every checkout of that type with a verified record checks that the verified identity’s name is consistent with the customer profile’s current
first_nameandlast_name. This applies to records you submit here just as it does to Soap’s own verification. Keep the profile on the customer’s legal first name and surname as shown on their ID, with no nicknames, middle names, initials or suffixes. A mismatch restricts the customer with reason codeKYC_DOES_NOT_MATCH_PROFILE_NAME; fix the profile with Update Customer and lift the restriction in the dashboard.
Required Fields
Required:customer_id, first_name, last_name, date_of_birth, address_line_1, city, state, postal_code, country, provider, verified
Optional: address_line_2, phone_number, email, last_four_ssn (accepted and stored, but not echoed back in the response)
| Field | Format |
|---|---|
state | Two uppercase letters (e.g., CA, NY) |
country | Three uppercase letters (e.g., USA). Required; there is no default. |
last_four_ssn | Exactly 4 digits (optional) |
curl -X POST "https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": null,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": true,
"last_four_ssn": "1234"
}'
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request['Authorization'] = 'Bearer YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
phone_number: '5551234567',
date_of_birth: '1990-01-15',
address_line_1: '123 Main Street',
address_line_2: nil,
city: 'San Francisco',
state: 'CA',
postal_code: '94102',
country: 'USA',
provider: 'plaid',
verified: true,
last_four_ssn: '1234'
}.to_json
response = http.request(request)
puts response.body
const axios = require('axios');
const upsertKyc = async () => {
try {
const response = await axios.post('https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert', {
customer_id: 'cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870',
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
phone_number: '5551234567',
date_of_birth: '1990-01-15',
address_line_1: '123 Main Street',
address_line_2: null,
city: 'San Francisco',
state: 'CA',
postal_code: '94102',
country: 'USA',
provider: 'plaid',
verified: true,
last_four_ssn: '1234'
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
console.log(response.data);
} catch (error) {
console.error(error);
}
};
upsertKyc();
import requests
import json
url = "https://api-sandbox.paywithsoap.com/api/v1/kyc/upsert"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
data = {
"customer_id": "cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": None,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": True,
"last_four_ssn": "1234"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
{
"id": "id_A3GuXEbThpqk2t6UTxEuoceVJyUEAX7V",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone_number": "5551234567",
"date_of_birth": "1990-01-15",
"address_line_1": "123 Main Street",
"address_line_2": null,
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "USA",
"provider": "plaid",
"verified": true
}
Authorizations
Bearer token authentication using your API key (key_...). Used for every endpoint except POST /api/v1/device_pings.
Body
Unique identifier for the customer
"cus_vi57KegYgcRqcGHqip8q6UZiqtrwMT870"
Customer's first name
1"John"
Customer's last name
1"Doe"
Customer's date of birth (YYYY-MM-DD)
"1990-01-15"
Primary address line
1"123 Main Street"
City name
1"San Francisco"
Two-letter state code (uppercase)
^[A-Z]{2}$"CA"
Postal or ZIP code
"94102"
Three-letter uppercase country code, for example USA. Required — there is no default.
^[A-Z]{3}$"USA"
KYC provider identifier used for verification
plaid, veriff, didit, sumsub, idology, seon, footprint, socure, geo_comply, acuity, surt, persona, shufti "plaid"
Whether the customer has been verified by the KYC provider. You can choose to provide an unverified identity by setting this field value to false. Hosted checkout reads the customer's most recent KYC record, so false sends an already-verified customer back through verification on their next checkout that requires KYC.
true
Customer's email address
"john@example.com"
Customer's phone number
"5551234567"
Secondary address line (apartment, suite, etc.)
"Apt 4B"
Last four digits of the customer's SSN (optional)
4^[0-9]{4}$"1234"
Response
KYC identity created or updated successfully
Unique identifier for the KYC identity record
"id_A3GuXEbThpqk2t6UTxEuoceVJyUEAX7V"
"John"
"Doe"
"john@example.com"
"5551234567"
"1990-01-15"
"123 Main Street"
null
"San Francisco"
"CA"
"94102"
"USA"
"your_kyc_provider"
true

