curl --request POST \
--url https://api.kemycard.com/v1/poa/{customerCode}/document \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form document=@example-fileimport requests
url = "https://api.kemycard.com/v1/poa/{customerCode}/document"
files = { "document": ("example-file", open("example-file", "rb")) }
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.kemycard.com/v1/poa/{customerCode}/document', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kemycard.com/v1/poa/{customerCode}/document",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kemycard.com/v1/poa/{customerCode}/document"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kemycard.com/v1/poa/{customerCode}/document")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kemycard.com/v1/poa/{customerCode}/document")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"customer_code": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"poa_status": "pending",
"verification_level": "verified",
"document_name": "electricity-bill.pdf",
"rejection_reason": "<string>",
"approved_at": "2023-11-07T05:31:56Z"
}
}{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient ops balance.",
"details": {
"required": 50,
"available": 10,
"balance_type": "cards_mastercard"
}
}
}{
"success": false,
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found.",
"details": null
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Missing required fields.",
"details": {}
},
"meta": {
"request_id": "a4f8e2c1b3d97056",
"mode": "test",
"timestamp": "2023-11-07T05:31:56Z"
}
}Submit Proof of Address
Submits the proof of address of a customer (verified → full) and starts its verification. The document must confirm the address you declared for this customer.
Send the file as multipart/form-data in the document field. Accepted formats: PDF, JPG, PNG — 10 MB maximum.
The call is refused when the customer is not active, when its KYC is not approved, when a proof of address
is already approved, or when one is already being verified.
The verification is billed only when it is approved (1.80 USD, debited from your others ops balance).
Submitting a document is free, but your others balance must cover the price of one verification.
The result is sent to your webhook endpoint (poa.approved, poa.rejected) and is available through the
POA status endpoint. After a rejection you can submit a new document.
curl --request POST \
--url https://api.kemycard.com/v1/poa/{customerCode}/document \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form document=@example-fileimport requests
url = "https://api.kemycard.com/v1/poa/{customerCode}/document"
files = { "document": ("example-file", open("example-file", "rb")) }
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.kemycard.com/v1/poa/{customerCode}/document', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.kemycard.com/v1/poa/{customerCode}/document",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.kemycard.com/v1/poa/{customerCode}/document"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.kemycard.com/v1/poa/{customerCode}/document")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kemycard.com/v1/poa/{customerCode}/document")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"customer_code": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"poa_status": "pending",
"verification_level": "verified",
"document_name": "electricity-bill.pdf",
"rejection_reason": "<string>",
"approved_at": "2023-11-07T05:31:56Z"
}
}{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient ops balance.",
"details": {
"required": 50,
"available": 10,
"balance_type": "cards_mastercard"
}
}
}{
"success": false,
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found.",
"details": null
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Missing required fields.",
"details": {}
},
"meta": {
"request_id": "a4f8e2c1b3d97056",
"mode": "test",
"timestamp": "2023-11-07T05:31:56Z"
}
}Authorizations
API key (sk_test_... or sk_live_...)
Path Parameters
Customer UUID
Body
Proof of address (utility bill, bank statement, government letter). PDF, JPG or PNG, 10 MB maximum