curl --request POST \
--url https://laso.finance/verify-card-issuer-link \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"code": "123456",
"consent_accepted": true
}
'import requests
url = "https://laso.finance/verify-card-issuer-link"
payload = {
"code": "123456",
"consent_accepted": True
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({code: '123456', consent_accepted: true})
};
fetch('https://laso.finance/verify-card-issuer-link', 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://laso.finance/verify-card-issuer-link",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'code' => '123456',
'consent_accepted' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$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://laso.finance/verify-card-issuer-link"
payload := strings.NewReader("{\n \"code\": \"123456\",\n \"consent_accepted\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<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))
}HttpResponse<String> response = Unirest.post("https://laso.finance/verify-card-issuer-link")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"code\": \"123456\",\n \"consent_accepted\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://laso.finance/verify-card-issuer-link")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"code\": \"123456\",\n \"consent_accepted\": true\n}"
response = http.request(request)
puts response.read_body{
"status": "linked",
"note": "The card issuer is linked. Next, the account holder shares their identity verification with the card issuer at https://laso.finance/agent/dashboard/verified/card, then the card balance can be funded with GET /fund-card-balance and cards created with POST /create-reloadable-card."
}{
"error": "That code is not correct.",
"code": "invalid_code",
"attempts_left": 3,
"terminal": false,
"hint": "Ask the account holder to check the code and enter it again."
}{
"error": "Identity verification is required before linking the card issuer.",
"code": "kyc_required",
"kyc_url": "https://verify.example.com/session/abc123",
"hint": "The account holder must complete identity verification before the card issuer can be linked. Send them kyc_url, then poll GET /get-kyc-status until kyc_verified is true."
}{
"error": "This card account is already linked to another Laso account. Disconnect it there first, then try again.",
"code": "linked_elsewhere",
"terminal": true,
"hint": "The card issuer account behind this code is linked to a different Laso account. The account holder must unlink it there first."
}{
"error": "Idempotency-Key reused with a different request",
"code": "idempotency_key_reused"
}{
"error": "Too many incorrect codes. Send a new code and try again.",
"code": "too_many_attempts",
"hint": "This code has been discarded after too many incorrect entries. Call POST /start-card-issuer-link to send a new one."
}Complete the card issuer link with the account holder's code
Completes the link with the one-time code the account holder received from POST /start-card-issuer-link. No session id is needed: the pending code is held per account, and only the newest one works.
The account holder, never the agent, receives and enters the code. Send your human to their own inbox (or phone) and have them type the code into your interface. Never try to read the account holder’s email or messages yourself, and never ask for their email password or access.
Consent. Completing the link records the account holder’s consent with the card issuer. Show them the card issuer’s connection disclosure next to the code input, and send consent_accepted: true only once they have accepted it.
Wrong codes. An incorrect code answers 400 invalid_code with attempts_left; the account holder can try again. After 5 incorrect entries, or once the code is 10 minutes old, it is discarded and a new one must be sent.
If the account is already linked this answers 200 with status: linked, so a retry after a lost response is safe. After linking, GET /get-card-issuer-status reads linked.
This route is free.
curl --request POST \
--url https://laso.finance/verify-card-issuer-link \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"code": "123456",
"consent_accepted": true
}
'import requests
url = "https://laso.finance/verify-card-issuer-link"
payload = {
"code": "123456",
"consent_accepted": True
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({code: '123456', consent_accepted: true})
};
fetch('https://laso.finance/verify-card-issuer-link', 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://laso.finance/verify-card-issuer-link",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'code' => '123456',
'consent_accepted' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$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://laso.finance/verify-card-issuer-link"
payload := strings.NewReader("{\n \"code\": \"123456\",\n \"consent_accepted\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<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))
}HttpResponse<String> response = Unirest.post("https://laso.finance/verify-card-issuer-link")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"code\": \"123456\",\n \"consent_accepted\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://laso.finance/verify-card-issuer-link")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"code\": \"123456\",\n \"consent_accepted\": true\n}"
response = http.request(request)
puts response.read_body{
"status": "linked",
"note": "The card issuer is linked. Next, the account holder shares their identity verification with the card issuer at https://laso.finance/agent/dashboard/verified/card, then the card balance can be funded with GET /fund-card-balance and cards created with POST /create-reloadable-card."
}{
"error": "That code is not correct.",
"code": "invalid_code",
"attempts_left": 3,
"terminal": false,
"hint": "Ask the account holder to check the code and enter it again."
}{
"error": "Identity verification is required before linking the card issuer.",
"code": "kyc_required",
"kyc_url": "https://verify.example.com/session/abc123",
"hint": "The account holder must complete identity verification before the card issuer can be linked. Send them kyc_url, then poll GET /get-kyc-status until kyc_verified is true."
}{
"error": "This card account is already linked to another Laso account. Disconnect it there first, then try again.",
"code": "linked_elsewhere",
"terminal": true,
"hint": "The card issuer account behind this code is linked to a different Laso account. The account holder must unlink it there first."
}{
"error": "Idempotency-Key reused with a different request",
"code": "idempotency_key_reused"
}{
"error": "Too many incorrect codes. Send a new code and try again.",
"code": "too_many_attempts",
"hint": "This code has been discarded after too many incorrect entries. Call POST /start-card-issuer-link to send a new one."
}Authorizations
Firebase ID token from /auth or any paid route, sent as a Bearer token: Authorization: Bearer <id_token> (the Bearer prefix is required).
Headers
Optional client-generated unique key (a UUID works) that makes this write safe to retry. A retry with the same key within 24 hours returns the recorded response of the original request, marked with an Idempotency-Replayed: true header, instead of performing the write again. Reusing a key with a different body or route is rejected with 422 (code: idempotency_key_reused); a retry that arrives while the original is still running gets 409 (code: idempotency_key_in_progress), so wait a moment and retry with the same key. Keys are scoped to the authenticated account.
255Body
Was this page helpful?