curl --request POST \
--url https://api-sandbox.finogates.com/v1/platform/card/add-card \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_holder_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_processing_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
'import requests
url = "https://api-sandbox.finogates.com/v1/platform/card/add-card"
payload = {
"user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_holder_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_processing_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
user_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
card_holder_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
card_processing_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a'
})
};
fetch('https://api-sandbox.finogates.com/v1/platform/card/add-card', 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-sandbox.finogates.com/v1/platform/card/add-card",
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([
'user_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'card_holder_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'card_processing_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://api-sandbox.finogates.com/v1/platform/card/add-card"
payload := strings.NewReader("{\n \"user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_holder_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_processing_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://api-sandbox.finogates.com/v1/platform/card/add-card")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_holder_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_processing_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-sandbox.finogates.com/v1/platform/card/add-card")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_holder_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_processing_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}"
response = http.request(request)
puts response.read_body{
"status_code": 123,
"data": "<unknown>",
"query_generated_time": 123
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Add Card
Get a ready-made web page link that lets one of your users add their own payment card. You show this page inside your own website (inside an iframe). The user types their card details on that page, and we store the card safely for them.
What you need to send
user_id— the user the card is being added for.card_processing_id— optional; pin the card to one specific approved card-processing account.metadata— optional opaque key/value object. We store it against the resulting card and send it back unchanged on the card reads and thepayment_method.card.added/.add_failedwebhooks, so you can map a card to your own end-user when many of your users share one Finogate user.
What you get back
user_id— the user this link is for.add_card_url— the link to load inside an iframe. It can be used once.expires_at— the time the link stops working (about 10 minutes away).
How you find out the result
- When the card is saved, we send your server an automatic notification (a
payment_method.card.addedwebhook) with the card details, theuser_id, and anymetadatayou supplied. This notification is the official way to know the card exists. - Check the
statuson that notification before charging the card:activemeans it is ready to use,pending(sent together withrequires_manual_review) means the card was saved but our team needs to review it first. - You get this notification once per card, and never again for that card.
When a reviewed card is decided, we send a different notification instead —
payment_method.card.review_approvedif it is accepted (the card is chargeable from then on) orpayment_method.card.review_rejectedif it is not. Both carry the samepayment_method_id, so listen for them too. - If something goes wrong on the page (the link expired, was tampered with, or the details didn’t pass our checks), nothing is saved and no success notification is sent. Simply call this endpoint again to get a fresh link — links cannot be renewed.
The link contains no details about which company processes the card behind the scenes. Treat it as a plain string with no meaning of its own.
curl --request POST \
--url https://api-sandbox.finogates.com/v1/platform/card/add-card \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_holder_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_processing_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
'import requests
url = "https://api-sandbox.finogates.com/v1/platform/card/add-card"
payload = {
"user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_holder_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"card_processing_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
user_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
card_holder_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
card_processing_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a'
})
};
fetch('https://api-sandbox.finogates.com/v1/platform/card/add-card', 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-sandbox.finogates.com/v1/platform/card/add-card",
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([
'user_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'card_holder_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'card_processing_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://api-sandbox.finogates.com/v1/platform/card/add-card"
payload := strings.NewReader("{\n \"user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_holder_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_processing_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://api-sandbox.finogates.com/v1/platform/card/add-card")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_holder_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_processing_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-sandbox.finogates.com/v1/platform/card/add-card")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_holder_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"card_processing_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}"
response = http.request(request)
puts response.read_body{
"status_code": 123,
"data": "<unknown>",
"query_generated_time": 123
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Authorizations
The access token received from the authorization server in the OAuth 2.0 flow.
Body
Request body for POST /v1/platform/card/add-card.
Mints a one-time hosted add-card page for the end user. The optional
metadata rides as a native JSON object in the request body.
The end-user the card is being added for. Must be an end_user belonging to the calling tenant.
Required. The Finogate user the card belongs to. Use this when user_id is the card-processing merchant owner and many of your end customers add cards under that one merchant — each card is tagged with its holder so you can list a single holder's cards. Must be a user of the calling tenant.
Optional. Pins the card to a specific approved card-processing merchant account (the id returned by GET /v1/platform/card-processing/users/{user_id}). Omit to use the user's deterministically selected default merchant.
Response
Successful Response
Standard response wrapper for single-object responses and errors.
Generic over the payload type. A route that declares
CommonResponse[SomeModel] gets the real data schema rendered in
OpenAPI/Swagger; a bare CommonResponse leaves data untyped.

