Linc, back to home

Developers

Integrate Linc into your application

A JSON REST API to send money, collect payments, manage virtual cards and receive signed notifications. Every request goes over HTTPS. No card data ever passes through your servers.

Get started

EnvironmentBase URLUse
Sandboxhttps://sandbox.api.linc.cdDevelopment and testing. sk_test_… keys, no real money, simulated partners.
Productionhttps://api.linc.cdReal operations. sk_live_… keys, available once your application is approved.

Every route starts with /v1. Request and response bodies are JSON (UTF-8). You can call the API from any language that can make an HTTPS request: the examples below use cURL, PHP, Python and JavaScript (Node.js 18+).

  1. Open a merchant account at merchant.linc.cd. Your test keys are available right away.
  2. Get your keys in Merchant portal › API & webhooks. The secret key is shown only once: keep it in a vault or an environment variable.
  3. Register your webhook URL in the same place, then test on the sandbox.
  4. Go live once your business verification (KYB) is approved: switch the base URL and the key.

Which integration?

You want to…AuthenticationMain routes
Collect payments from your customers (website, app, invoice)Merchant secret key sk_/v1/payment-links
Act on behalf of a Linc customer: transfers, payments, virtual card, top-upCustomer token (15-min JWT + refresh token)/v1/auth, /v1/quotes, /v1/transfers, /v1/cards
Build an app for a Linc merchant or agentPro token (password + TOTP)/v1/pro/auth
Connect an agent network's platform, server to serverComing soon: scoped keys, signed requests and allowed IP addresses. Write to sales@linc.cd.

The customer API always acts for an identified customer, who confirms every sensitive operation with their own second factor. Linc never issues a customer token to a third party without the customer's consent.

Authentication

Merchant secret key

Send the key in the Authorization header. A missing or invalid key returns 401 api_key_invalid. Never use the secret key in a browser or a mobile app: it stays on your server.

curl https://sandbox.api.linc.cd/v1/payment-links/INV-7K2Q4F \
  -H "Authorization: Bearer $LINC_SECRET_KEY"

Allowed IP addresses

Secret keys only work from the IP addresses of your servers. Declare them in the “Technical integration” step of your file, then manage them in your merchant space, “API & webhooks › Allowed IP addresses”. Each change is confirmed with your authenticator app.

  • Production (sk_live_): the list is required to generate the keys. A call from any other address returns 403 ip_not_allowed.
  • Sandbox (sk_test_): the list is optional. Empty, any address is accepted, including the test area of this page.
  • Up to 10 IPv4 (203.0.113.10) or IPv6 (2001:db8::10) addresses, or CIDR ranges (198.51.100.0/28; /8 to /32 in IPv4, /32 to /128 in IPv6).
  • The address checked is the one that connects to Linc: the outbound address of your server, or of your NAT gateway or outbound proxy. An X-Forwarded-For header sent by your code is ignored.
  • Moving to another host? Add the new address before the switch, then remove the old one.
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json

{"type": "https://docs.linc.cd/erreurs/ip_not_allowed", "status": 403, "code": "ip_not_allowed",
 "title": "IP address not allowed for this key. Add your server's address in “API & webhooks › Allowed IP addresses”."}

Customer token: two-step sign-in

  1. POST /v1/auth/login with the identifier (phone or e-mail) and password, and the X-Device-Id header (a stable installation identifier).
  2. Known device: 200 response with the tokens. New device: 202 two_factor_required response with a pendingLoginId and the available methods (totp, sms, backup_code).
  3. For SMS, request the code first: POST /v1/auth/login/{pendingLoginId}/sms. Then send the code: POST /v1/auth/login/{pendingLoginId}/verify.
  4. Use accessToken (valid 15 minutes) in Authorization: Bearer …. Before it expires, call POST /v1/auth/refresh: the refresh token rotates, so keep the new one and discard the old one.
# 1. Password
curl -X POST https://sandbox.api.linc.cd/v1/auth/login \
  -H "Content-Type: application/json" -H "X-Device-Id: $DEVICE_ID" \
  -d '{"identifier": "+243810000000", "password": "…"}'
# → 202 {"status":"two_factor_required","pendingLoginId":"0192…","methods":["totp","sms"],"expiresAt":"…"}

# 2. Second factor
curl -X POST https://sandbox.api.linc.cd/v1/auth/login/$PENDING_ID/verify \
  -H "Content-Type: application/json" -H "X-Device-Id: $DEVICE_ID" \
  -d '{"method": "totp", "code": "123456"}'
# → 200 {"tokenType":"Bearer","accessToken":"eyJ…","expiresIn":900,"refreshToken":"…","refreshExpiresIn":…}

# 3. Refresh
curl -X POST https://sandbox.api.linc.cd/v1/auth/refresh \
  -H "Content-Type: application/json" -d '{"refreshToken": "…"}'
<?php
function linc(string $method, string $path, array $body = null, array $headers = []): array
{
    $ch = curl_init('https://sandbox.api.linc.cd'.$path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => array_merge(['Content-Type: application/json', 'Accept: application/json'], $headers),
        CURLOPT_POSTFIELDS => null === $body ? null : json_encode($body),
    ]);
    $raw = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    return [$status, json_decode($raw, true)];
}

$device = ['X-Device-Id: '.getenv('LINC_DEVICE_ID')];
[$status, $login] = linc('POST', '/v1/auth/login', ['identifier' => '+243810000000', 'password' => $password], $device);
if (202 === $status) {
    [, $login] = linc('POST', "/v1/auth/login/{$login['pendingLoginId']}/verify", ['method' => 'totp', 'code' => $totpCode], $device);
}
$auth = ['Authorization: Bearer '.$login['accessToken']];
import os, requests

API = "https://sandbox.api.linc.cd"
device = {"X-Device-Id": os.environ["LINC_DEVICE_ID"]}

r = requests.post(f"{API}/v1/auth/login", json={"identifier": "+243810000000", "password": password}, headers=device, timeout=30)
if r.status_code == 202:
    pending = r.json()["pendingLoginId"]
    r = requests.post(f"{API}/v1/auth/login/{pending}/verify", json={"method": "totp", "code": totp_code}, headers=device, timeout=30)
r.raise_for_status()
tokens = r.json()
auth = {"Authorization": f"Bearer {tokens['accessToken']}"}
const API = "https://sandbox.api.linc.cd";
const device = { "Content-Type": "application/json", "X-Device-Id": process.env.LINC_DEVICE_ID };

let res = await fetch(`${API}/v1/auth/login`, {
  method: "POST", headers: device,
  body: JSON.stringify({ identifier: "+243810000000", password }),
});
if (res.status === 202) {
  const { pendingLoginId } = await res.json();
  res = await fetch(`${API}/v1/auth/login/${pendingLoginId}/verify`, {
    method: "POST", headers: device,
    body: JSON.stringify({ method: "totp", code: totpCode }),
  });
}
const { accessToken, refreshToken } = await res.json();
const auth = { Authorization: `Bearer ${accessToken}` };

Conventions

Idempotency
Every financial POST requires the Idempotency-Key header (8 to 255 characters, one UUID per operation). The key is kept for 24 hours: sending the same request with the same key never creates a duplicate. The same key with a different body returns idempotency_key_reused.
Amounts
As input, a decimal string: "150.00". As output, an object {"amount": 15000, "currency": "USD", "display": "150,00 $"} where amount is an integer in minor units. Never use floating-point numbers for money.
Currencies and countries
ISO 4217 codes (USD, CDF) and ISO 3166 alpha-2 codes (CI, SN…). Open countries and payout methods are listed by GET /v1/corridors (public).
Second factor
Sensitive operations (transfer, payment, card, beneficiary) take a "twoFactor": {"method": "totp", "code": "••••••"} object. Without it, the response is two_factor_required: ask the customer for the code, then resend the request with the same Idempotency-Key.
Mobile apps
Send X-Device-Id, X-App-Id, X-App-Platform and X-App-Version. When the policy requires it, sensitive operations also need X-Linc-Attestation (attested device).
Asynchronous
A transfer or payment is accepted (202) and then processed: track its status by webhook or GET, never assume it succeeded.

Send a transfer

Example: 150 USD from Airtel Money (DRC) to an Orange Money wallet in Côte d'Ivoire.

1Amount and countryThe customer picks the country and payout method.
2QuoteFees, rate, total debited, amount received. Valid 60 s.
3BeneficiaryMobile money number, bank account or card.
4ConfirmationSource of funds and 6-digit code (2FA).
5TrackingCollection, payout, delivery, in real time.
  1. POST /v1/quotes: amount, currency, country and payout method. Response: id, send, fee, vat, levy, total, receive, rate, expiresAt. Show them to the customer as returned.
  2. POST /v1/beneficiaries (once per beneficiary): name, country, method and details in details.
  3. POST /v1/transfers before the quote expires: quoteId, beneficiaryId, source, purpose and twoFactor. 202 response with the LP-XXXXXX reference.
  4. GET /v1/transfers/{reference}: status is in_progress, delivered, failed, refunded or on_hold, with the steps.
# 1. Quote
curl -X POST https://sandbox.api.linc.cd/v1/quotes \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"amount": "150.00", "currency": "USD", "destinationCountry": "CI", "payoutMethod": "mobile_money", "sourceType": "mobile_money"}'

# 2. Beneficiary
curl -X POST https://sandbox.api.linc.cd/v1/beneficiaries \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -d '{"fullName": "Bastian Kelyan", "country": "CI", "payoutMethod": "mobile_money",
       "details": {"msisdn": "+2250700000000", "provider": "orange", "relationship": "family"}}'

# 3. Transfer, confirmed with the second factor
curl -X POST https://sandbox.api.linc.cd/v1/transfers \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"quoteId": "'$QUOTE_ID'", "beneficiaryId": "'$BENEFICIARY_ID'",
       "source": {"type": "mobile_money", "provider": "airtel", "msisdn": "+243970000000"},
       "purpose": "family_support",
       "twoFactor": {"method": "totp", "code": "••••••"}}'
# → 202 {"reference": "LP-8QK2ZD", "status": "in_progress", "steps": […], …}

# 4. Tracking
curl https://sandbox.api.linc.cd/v1/transfers/LP-8QK2ZD -H "Authorization: Bearer $ACCESS_TOKEN"
<?php
// linc(): see the authentication example
$idem = fn () => 'Idempotency-Key: '.bin2hex(random_bytes(16));

[, $quote] = linc('POST', '/v1/quotes', [
    'amount' => '150.00', 'currency' => 'USD',
    'destinationCountry' => 'CI', 'payoutMethod' => 'mobile_money', 'sourceType' => 'mobile_money',
], [...$auth, $idem()]);
// Show $quote['fee']['display'], $quote['total']['display'], $quote['receive']['display']

[$status, $transfer] = linc('POST', '/v1/transfers', [
    'quoteId' => $quote['id'],
    'beneficiaryId' => $beneficiaryId,
    'source' => ['type' => 'mobile_money', 'provider' => 'airtel', 'msisdn' => '+243970000000'],
    'purpose' => 'family_support',
    'twoFactor' => ['method' => 'totp', 'code' => $code],
], [...$auth, $idem()]);

if (202 !== $status) {
    throw new RuntimeException($transfer['code'].': '.$transfer['title']);
}
echo $transfer['reference']; // LP-XXXXXX
import uuid

def post(path, body):
    headers = {**auth, "Idempotency-Key": str(uuid.uuid4())}
    return requests.post(f"{API}{path}", json=body, headers=headers, timeout=30)

quote = post("/v1/quotes", {
    "amount": "150.00", "currency": "USD",
    "destinationCountry": "CI", "payoutMethod": "mobile_money", "sourceType": "mobile_money",
}).json()
print(quote["fee"]["display"], quote["total"]["display"], quote["receive"]["display"])

r = post("/v1/transfers", {
    "quoteId": quote["id"],
    "beneficiaryId": beneficiary_id,
    "source": {"type": "mobile_money", "provider": "airtel", "msisdn": "+243970000000"},
    "purpose": "family_support",
    "twoFactor": {"method": "totp", "code": code},
})
if r.status_code != 202:
    problem = r.json()
    raise RuntimeError(f"{problem['code']}: {problem['title']}")
reference = r.json()["reference"]  # LP-XXXXXX
import { randomUUID } from "node:crypto";

const post = (path, body) => fetch(`${API}${path}`, {
  method: "POST",
  headers: { ...auth, "Content-Type": "application/json", "Idempotency-Key": randomUUID() },
  body: JSON.stringify(body),
});

const quote = await (await post("/v1/quotes", {
  amount: "150.00", currency: "USD",
  destinationCountry: "CI", payoutMethod: "mobile_money", sourceType: "mobile_money",
})).json();

const res = await post("/v1/transfers", {
  quoteId: quote.id,
  beneficiaryId,
  source: { type: "mobile_money", provider: "airtel", msisdn: "+243970000000" },
  purpose: "family_support",
  twoFactor: { method: "totp", code },
});
if (res.status !== 202) {
  const problem = await res.json();
  throw new Error(`${problem.code}: ${problem.title}`);
}
const { reference } = await res.json(); // LP-XXXXXX

Possible sources: mobile_money (Airtel Money, M-Pesa, Orange Money, Afrimoney), wallet (Linc balance, wallet-mode account) and card when that flow is open. Destinations: mobile_money, bank_account or card. Available countries and methods depend on the open corridors: read them from GET /v1/corridors instead of hard-coding them.

Collect a payment (merchant)

1Your siteYour server creates the payment link.
2Linc pageThe customer opens app.linc.cd/pay/INV-… or scans the QR.
3PaymentBalance, mobile money or card, confirmed by the customer.
4ReceiptYou receive payment.succeeded.
  1. POST /v1/payment-links with your secret key: amount, description, expires_in (24h, 7d or 30d). The response contains id (INV-XXXXXX), url and qr.
  2. Redirect the customer to url, show the QR or send the link by SMS.
  3. Fulfil the order when you receive the payment.succeeded webhook (not when the customer returns to your site). As a fallback, read the status with GET /v1/payment-links/{id}: open, paid, expired or cancelled.
curl -X POST https://sandbox.api.linc.cd/v1/payment-links \
  -H "Authorization: Bearer $LINC_SECRET_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10452" \
  -d '{"amount": "25.00", "description": "Order no. 10452", "expires_in": "24h"}'
# → 201 {"id": "INV-7K2Q4F", "object": "payment_link", "status": "open", "livemode": false,
#        "amount": {"amount": 2500, "currency": "USD", "display": "25,00 $"},
#        "url": "https://app.linc.cd/pay/INV-7K2Q4F", "qr": "…", "expires_at": "…"}
<?php
[$status, $link] = linc('POST', '/v1/payment-links',
    ['amount' => '25.00', 'description' => 'Order no. 10452', 'expires_in' => '24h'],
    ['Authorization: Bearer '.getenv('LINC_SECRET_KEY'), 'Idempotency-Key: order-10452'],
);
header('Location: '.$link['url'], true, 303);
r = requests.post(f"{API}/v1/payment-links",
    json={"amount": "25.00", "description": "Order no. 10452", "expires_in": "24h"},
    headers={"Authorization": f"Bearer {os.environ['LINC_SECRET_KEY']}", "Idempotency-Key": "order-10452"},
    timeout=30)
r.raise_for_status()
link = r.json()
redirect_to(link["url"])  # https://app.linc.cd/pay/INV-…
const res = await fetch(`${API}/v1/payment-links`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LINC_SECRET_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "order-10452",
  },
  body: JSON.stringify({ amount: "25.00", description: "Order no. 10452", expires_in: "24h" }),
});
const link = await res.json();
response.redirect(303, link.url);

A link created with a test key (livemode: false) can never be paid for real. In the customer app, paying a link or a QR uses POST /v1/merchant-payments/resolve (read the QR or link), then POST /v1/merchant-payments (pay, with the second factor). Card payments go through a hosted card page with 3-D Secure: you never handle the card number.

Create a virtual card

Available to a customer in wallet mode with KYC level 2. The card is funded from the Linc balance.

1NetworkVisa or Mastercard, name on the card.
2Confirmation6-digit code (2FA).
3CardLast 4 digits, status, limits.
4DetailsShown by the issuer's secure widget.
curl -X POST https://sandbox.api.linc.cd/v1/cards \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"network": "visa", "embossedName": "AMANI K", "twoFactor": {"method": "totp", "code": "••••••"}}'
# → 201 {"id": "0192…", "last4": "4821", "network": "visa", "currency": "USD", "status": "active", "limits": {…}, …}

# Freeze, unfreeze
curl -X POST https://sandbox.api.linc.cd/v1/cards/$CARD_ID/freeze   -H "Authorization: Bearer $ACCESS_TOKEN"
curl -X POST https://sandbox.api.linc.cd/v1/cards/$CARD_ID/unfreeze -H "Authorization: Bearer $ACCESS_TOKEN"
<?php
[$status, $card] = linc('POST', '/v1/cards', [
    'network' => 'visa',
    'embossedName' => 'AMANI K',
    'twoFactor' => ['method' => 'totp', 'code' => $code],
], [...$auth, $idem()]);
echo $card['network'].' •••• '.$card['last4'];
card = post("/v1/cards", {
    "network": "visa",
    "embossedName": "AMANI K",
    "twoFactor": {"method": "totp", "code": code},
}).json()
print(card["network"], "••••", card["last4"])
const card = await (await post("/v1/cards", {
  network: "visa",
  embossedName: "AMANI K",
  twoFactor: { method: "totp", code },
})).json();
console.log(`${card.network} •••• ${card.last4}`);

Linc never returns the full card number, the CVV or the expiry date. To show them, POST /v1/cards/{id}/reveal (with the second factor) opens a 60-second session for the issuer's widget or SDK, which displays the details directly to the customer. Other routes: GET /v1/cards, GET /v1/cards/{id}/transactions, /replace, /terminate.

Receive webhooks

Linc sends a JSON POST to the URL registered in Merchant portal › API & webhooks (HTTPS required) for every event:

EventWhen
payment.succeededA payment is confirmed by the partner. Fulfil the order.
payment.refundedA payment is refunded, fully or partially.
payment.disputedA card payment is disputed.
settlement.paidThe daily settlement is paid to your bank account, net of commission.

Headers sent: X-Linc-Event (type), X-Linc-Delivery (unique event identifier) and X-Linc-Signature:

X-Linc-Signature: t=1790712000,v1=5f1c…e9a2
# v1 = hex HMAC-SHA256, key = webhook secret (whsec_…), message = "{t}.{raw body}"

{
  "id": "evt_0192a7c4…",
  "type": "payment.succeeded",
  "created": 1790712000,
  "merchant": "M-4K7Q2",
  "data": {
    "id": "…", "object": "payment", "status": "succeeded",
    "amount": "25.00", "currency": "USD", "commission": "0.38",
    "payment_link": "INV-7K2Q4F", "method": "mobile_money", "provider": "airtel", …
  }
}

Always verify the signature on the raw body, before decoding it, and reject a timestamp older than 5 minutes:

<?php
$body = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_LINC_SIGNATURE'] ?? '';
$secret = getenv('LINC_WEBHOOK_SECRET');

if (1 !== preg_match('/^t=(\d+),v1=([a-f0-9]{64})$/', $header, $m)
    || abs(time() - (int) $m[1]) > 300
    || !hash_equals(hash_hmac('sha256', $m[1].'.'.$body, $secret), $m[2])) {
    http_response_code(400);
    exit;
}

$event = json_decode($body, true);
// Skip an event already processed ($event['id']), then process it in a queue
http_response_code(200);
import hashlib, hmac, os, re, time
from flask import Flask, abort, request

app = Flask(__name__)
SECRET = os.environ["LINC_WEBHOOK_SECRET"].encode()

@app.post("/webhooks/linc")
def linc_webhook():
    body = request.get_data()  # raw body
    m = re.fullmatch(r"t=(\d+),v1=([a-f0-9]{64})", request.headers.get("X-Linc-Signature", ""))
    if not m or abs(time.time() - int(m[1])) > 300:
        abort(400)
    expected = hmac.new(SECRET, m[1].encode() + b"." + body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, m[2]):
        abort(400)
    event = request.get_json()
    # Skip an event already processed (event["id"]), then process it in a queue
    return "", 200
import crypto from "node:crypto";
import express from "express";

const app = express();
app.post("/webhooks/linc", express.raw({ type: "application/json" }), (req, res) => {
  const m = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(req.get("X-Linc-Signature") ?? "");
  if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return res.sendStatus(400);
  const expected = crypto.createHmac("sha256", process.env.LINC_WEBHOOK_SECRET)
    .update(`${m[1]}.`).update(req.body).digest("hex");
  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]))) return res.sendStatus(400);
  const event = JSON.parse(req.body);
  // Skip an event already processed (event.id), then process it in a queue
  res.sendStatus(200);
});
  • Reply 2xx within 10 seconds, then process in the background.
  • Without a 2xx reply, Linc resends the event after 1 min, 5 min, 30 min, 2 h and 6 h.
  • The same event may arrive twice: deduplicate on id (or X-Linc-Delivery).
  • Delivery order is not guaranteed: rely on the status inside data.
  • The webhook secret can be renewed in the merchant portal; so can the API keys (rotation).

Test space

Check your key and see the real API answers without writing code. Calls go from your browser to the sandbox https://sandbox.api.linc.cd, which accepts test keys only: no real money, no payable link.

Type only an sk_test_… key. An sk_live_… key is refused before anything is sent. The key stays in this page: it is never stored, logged or put in the address. Close the tab to erase it.

Create a test payment link
Read a payment link

Result

Type your test key, then click “Check the key”.

Equivalent request

Sign and verify a webhook

Test your verification code: paste the raw body received and the X-Linc-Signature header, or generate a header for a test body. The computation runs in your browser: nothing is sent. Preferably use the secret of your test webhook.

JSON files

Request and response examples that follow the API contract. Download them for your tests, screen mock-ups or simulators (file names are in French).

Sandbox Postman collection

Import the collection into Postman, then fill in secretKey (test key) or the credentials of a test account, and deviceId. Tokens, quotes, beneficiaries and references are saved automatically from one request to the next.

Authentication

Transfer

Payment and card

Webhooks and errors

Errors

Errors use the application/problem+json format (RFC 9457), with a stable code to test in your code and a readable title:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{"type": "https://docs.linc.cd/erreurs/validation_failed", "title": "Some fields are invalid. Correct them, then try again.",
 "status": 422, "code": "validation_failed",
 "violations": [{"field": "amount", "message": "…"}]}
CodeWhat to do
validation_failedFix the fields listed in violations.
api_key_invalidCheck the key and the environment (sk_test_ on the sandbox, sk_live_ in production).
ip_not_allowedThe call comes from an IP address that is not among your allowed addresses: add your server's address in “API & webhooks”.
two_factor_requiredAsk the customer for the code and resend the request with twoFactor.
quote_expiredThe quote is older than 60 seconds: request a new one and show it to the customer.
quote_already_usedThis quote was already used: track the existing transfer.
idempotency_key_requiredAdd the Idempotency-Key header.
idempotency_key_reusedSame key, different body: generate a new key for a new operation.
idempotency_in_progressThe first request is still running: retry in a few seconds.
attestation_requiredSend the device's X-Linc-Attestation assertion.
app_update_requiredUpdate the app (minimumVersion).
rate_limitedToo many requests: wait, then retry with an increasing delay.

Help and security

  • Never put a secret key, webhook secret or token in source code, a mobile app or a browser.
  • Log the code and the reference (LP-…, INV-…), never personal data.
  • Full documentation generated from the OpenAPI contract, and the developer space, are coming soon.
  • Technical questions: support@linc.cd. Partnerships and production access: sales@linc.cd.

POST /v1/auth/register

Create a customer account

The detailed descriptions of this sheet are written in French.

Crée le compte et envoie un code SMS de vérification du téléphone.

Authentication: None (public route)

Parameters

NameInTypeRequiredDescription
X-Device-Idheaderstringno

Identifiant d'installation de l'application. Un appareil inconnu déclenche la double authentification.

Request body

NameTypeRequiredDescription
fullNamestringyes
phonestringyes

Numéro de téléphone, par exemple +243812345678.

emailstring (email)yes
passwordstringyes

8 caractères au moins avec un chiffre. Refusé s'il figure dans une fuite connue.

acceptTermsbooleanyes

Case « J'ai lu et j'accepte les Conditions générales d'utilisation » (versions : GET /v1/legal).

acceptPrivacybooleanyes

Case « J'ai lu la Politique de confidentialité et j'accepte le traitement de mes données décrit ».

acceptAmlbooleanyes

Case « J'ai lu la Politique LBC/FT et je m'engage à respecter mes obligations » (informations exactes, compte utilisé pour soi-même, fonds d'origine licite). Les trois cases sont distinctes, non cochées par défaut, et le serveur refuse l'inscription sans les trois (422 validation_failed, un champ par case manquante). La preuve de chaque acceptation (version, date, canal, adresse IP, appareil, session) est conservée ; le canal est la plateforme de l'application (X-App-Platform : android, ios).

residenceCountrystringno

Pays de résidence (ISO 3166 alpha-2) parmi GET /v1/origin-countries. Par défaut, le pays du téléphone. Un autre pays est refusé (residence_not_allowed, « Linc est disponible pour les résidents de la RD Congo. »), un téléphone d'un autre pays aussi (phone_not_residence).

Request example

{
  "fullName": "texte",
  "phone": "+243810000000",
  "email": "client@example.com",
  "password": "••••••••",
  "acceptTerms": true,
  "acceptPrivacy": true,
  "acceptAml": true
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
  "fullName": "texte",
  "phone": "+243810000000",
  "email": "client@example.com",
  "password": "••••••••",
  "acceptTerms": true,
  "acceptPrivacy": true,
  "acceptAml": true
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/register');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "fullName": "texte",
  "phone": "+243810000000",
  "email": "client@example.com",
  "password": "••••••••",
  "acceptTerms": true,
  "acceptPrivacy": true,
  "acceptAml": true
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/register",
    json={
        "fullName": "texte",
        "phone": "+243810000000",
        "email": "client@example.com",
        "password": "••••••••",
        "acceptTerms": True,
        "acceptPrivacy": True,
        "acceptAml": True
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/register", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "fullName": "texte",
    "phone": "+243810000000",
    "email": "client@example.com",
    "password": "••••••••",
    "acceptTerms": true,
    "acceptPrivacy": true,
    "acceptAml": true
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "purpose": "phone_verification",
  "sentTo": "texte",
  "expiresAt": "2026-10-01T09:30:00Z",
  "remainingAttempts": 0
}

Answers and errors

StatusMeaning
201

Compte créé. Code SMS envoyé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/origin-countries

List the countries of residence accepted at sign-up

The detailed descriptions of this sheet are written in French.

Pays d'origine autorisés : l'agrément de la BCC couvre les envois depuis la RD Congo, seule proposée par défaut (default). Le téléphone doit être un numéro du pays de résidence (callingCode). Public.

Authentication: None (public route)

Code example

curl "https://sandbox.api.linc.cd/v1/origin-countries"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/origin-countries');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/origin-countries",
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/origin-countries", {
  method: "GET",
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "countries": [
    {
      "country": "CD",
      "name": "Congo-Kinshasa",
      "callingCode": "+243",
      "default": true
    }
  ]
}

Answers and errors

StatusMeaning
200

Pays de résidence acceptés.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/auth/register/resend

Resend the verification code

The detailed descriptions of this sheet are written in French.

Envoie un nouveau code SMS pour la vérification du téléphone.

Authentication: None (public route)

Request body

NameTypeRequiredDescription
challengeIdstring (uuid)yes

Request example

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/register/resend" \
  -H "Content-Type: application/json" \
  -d '{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/register/resend');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/register/resend",
    json={
        "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/register/resend", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "purpose": "phone_verification",
  "sentTo": "texte",
  "expiresAt": "2026-10-01T09:30:00Z",
  "remainingAttempts": 0
}

Answers and errors

StatusMeaning
201

Nouveau code envoyé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/auth/verify-phone

Verify the phone number

The detailed descriptions of this sheet are written in French.

Valide le code SMS, active le compte et ouvre une session mobile.

Authentication: None (public route)

Parameters

NameInTypeRequiredDescription
X-Device-Idheaderstringno

Identifiant d'installation de l'application. Un appareil inconnu déclenche la double authentification.

Request body

NameTypeRequiredDescription
challengeIdstring (uuid)yes
codestringyes

Code à 6 chiffres reçu par SMS.

Request example

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "code": "••••••"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/verify-phone" \
  -H "Content-Type: application/json" \
  -d '{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "code": "••••••"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/verify-phone');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "code": "••••••"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/verify-phone",
    json={
        "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
        "code": "••••••"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/verify-phone", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "code": "••••••"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "tokenType": "Bearer",
  "accessToken": "…",
  "expiresIn": 0,
  "refreshToken": "…",
  "refreshExpiresIn": 0
}

Answers and errors

StatusMeaning
200

Téléphone vérifié. Jetons de session.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/auth/login

Sign in

The detailed descriptions of this sheet are written in French.

Connexion par téléphone ou e-mail. Sur un appareil connu : jetons de session (200). Sur un nouvel appareil : double authentification requise (202), à terminer avec POST /v1/auth/login/{pendingLoginId}/verify.

Authentication: None (public route)

Parameters

NameInTypeRequiredDescription
X-Device-Idheaderstringno

Identifiant d'installation de l'application. Un appareil inconnu déclenche la double authentification.

Request body

NameTypeRequiredDescription
identifierstringyes

Téléphone ou e-mail.

passwordstringyes

Request example

{
  "identifier": "+243810000000",
  "password": "••••••••"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
  "identifier": "+243810000000",
  "password": "••••••••"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/login');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "identifier": "+243810000000",
  "password": "••••••••"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/login",
    json={
        "identifier": "+243810000000",
        "password": "••••••••"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/login", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "identifier": "+243810000000",
    "password": "••••••••"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "status": "two_factor_required",
  "pendingLoginId": "0192a7c4-2c9d-7e41-a3b5-6f7e8d9c0b12",
  "methods": [
    "totp",
    "sms",
    "backup_code"
  ],
  "expiresAt": "2026-09-29T14:05:00+00:00"
}

Answers and errors

StatusMeaning
200

Connexion réussie.

202

Double authentification requise.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/auth/login/{pendingLoginId}/sms

Receive the sign-in code by SMS

The detailed descriptions of this sheet are written in French.

Envoie un code SMS pour terminer une connexion en attente.

Authentication: None (public route)

Parameters

NameInTypeRequiredDescription
pendingLoginIdpathstringyes

Identifiant de la connexion en attente.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/sms"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/sms');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/sms",
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/sms", {
  method: "POST",
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "purpose": "phone_verification",
  "sentTo": "texte",
  "expiresAt": "2026-10-01T09:30:00Z",
  "remainingAttempts": 0
}

Answers and errors

StatusMeaning
201

Code envoyé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/auth/login/{pendingLoginId}/verify

Finish signing in with the second factor

The detailed descriptions of this sheet are written in French.

Vérifie le code TOTP, SMS ou de secours et ouvre la session sur ce nouvel appareil.

Authentication: None (public route)

Parameters

NameInTypeRequiredDescription
pendingLoginIdpathstringyes

Identifiant de la connexion en attente.

X-Device-Idheaderstringno

Identifiant d'installation de l'application. Un appareil inconnu déclenche la double authentification.

Request body

NameTypeRequiredDescription
methodstringyes

totp · sms · backup_code

codestringyes
challengeIdstring (uuid)no

Request example

{
  "method": "totp",
  "code": "••••••"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify" \
  -H "Content-Type: application/json" \
  -d '{
  "method": "totp",
  "code": "••••••"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "method": "totp",
  "code": "••••••"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify",
    json={
        "method": "totp",
        "code": "••••••"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/login/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "method": "totp",
    "code": "••••••"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "tokenType": "Bearer",
  "accessToken": "eyJ…",
  "expiresIn": 900,
  "refreshToken": "…",
  "refreshExpiresIn": 2592000
}

Answers and errors

StatusMeaning
200

Connexion réussie.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/auth/refresh

Renew the tokens

The detailed descriptions of this sheet are written in French.

Échange le jeton de rafraîchissement contre une nouvelle paire (rotation). Un jeton réutilisé révoque la session.

Authentication: None (public route)

Request body

NameTypeRequiredDescription
refreshTokenstringyes

Request example

{
  "refreshToken": "…"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/refresh" \
  -H "Content-Type: application/json" \
  -d '{
  "refreshToken": "…"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/refresh');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "refreshToken": "…"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/refresh",
    json={
        "refreshToken": "…"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/refresh", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "refreshToken": "…"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "tokenType": "Bearer",
  "accessToken": "eyJ…",
  "expiresIn": 900,
  "refreshToken": "…",
  "refreshExpiresIn": 2592000
}

Answers and errors

StatusMeaning
200

Nouvelle paire de jetons.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/auth/logout

Sign out

The detailed descriptions of this sheet are written in French.

Révoque le jeton de rafraîchissement.

Authentication: None (public route)

Request body

NameTypeRequiredDescription
refreshTokenstringyes

Request example

{
  "refreshToken": "…"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/auth/logout" \
  -H "Content-Type: application/json" \
  -d '{
  "refreshToken": "…"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/auth/logout');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "refreshToken": "…"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/auth/logout",
    json={
        "refreshToken": "…"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/auth/logout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "refreshToken": "…"
  }),
});
console.log(answer.status, await answer.text());

Answer example 204

Session fermée.

Answers and errors

StatusMeaning
204

Session fermée.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/me

Show my profile

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/me" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/me",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "fullName": "texte",
  "phone": "+243810000000",
  "email": "client@example.com",
  "status": "pending_verification",
  "kycLevel": 1,
  "accountMode": "wallet",
  "twoFactor": {
    "totp": true,
    "sms": true,
    "backupCodesRemaining": true
  },
  "consents": {
    "termsAcceptanceRequired": true,
    "pending": [
      {
        "document": "terms",
        "version": "texte"
      }
    ],
    "biometric": true
  }
}

Answers and errors

StatusMeaning
200

Profil du client connecté.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

PUT /v1/me/locale

Choose the account language

The detailed descriptions of this sheet are written in French.

Langue choisie dans le profil de l'application (fr ou en). Les e-mails et SMS sont écrits dans cette langue. Les messages d'erreur de l'API suivent l'en-tête Accept-Language.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
localestringyes

fr · en

Request example

{
  "locale": "fr"
}

Code example

curl -X PUT "https://sandbox.api.linc.cd/v1/me/locale" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "locale": "fr"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/locale');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "locale": "fr"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.put(
    "https://sandbox.api.linc.cd/v1/me/locale",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "locale": "fr"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/locale", {
  method: "PUT",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "locale": "fr"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "locale": "fr"
}

Answers and errors

StatusMeaning
200

Langue enregistrée.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/consents/contract

Accept the new version of the contract documents

The detailed descriptions of this sheet are written in French.

Accepte les versions actuelles des documents dont une nouvelle version attend l'acceptation (GET /v1/me, consents.pending) : une case par document en attente (Conditions générales, Politique de confidentialité, Politique LBC/FT), jamais cochée à la place du client. Le contrat d'utilisation qui les liste est accepté avec eux ; il a sa propre case (acceptContract) quand il est seul à avoir changé. Sans acceptation, le client peut lire (solde, historique) mais ne peut lancer aucune opération (403 contract_acceptance_required). Restent ouverts : la session, les appareils, le KYC, les réclamations et le retrait de ses propres fonds (POST /v1/wallet/withdrawal-codes, son annulation et le code SMS purpose: withdrawal).

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
acceptTermsbooleanno

Case des Conditions générales, obligatoire si elles sont en attente.

acceptPrivacybooleanno

Case de la Politique de confidentialité, obligatoire si elle est en attente.

acceptAmlbooleanno

Case de la Politique LBC/FT, obligatoire si elle est en attente.

acceptContractbooleanno

Case du contrat d'utilisation, obligatoire seulement s'il est seul en attente.

Request example

{
  "acceptTerms": false,
  "acceptPrivacy": false,
  "acceptAml": false,
  "acceptContract": false
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/consents/contract" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "acceptTerms": false,
  "acceptPrivacy": false,
  "acceptAml": false,
  "acceptContract": false
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/consents/contract');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "acceptTerms": false,
  "acceptPrivacy": false,
  "acceptAml": false,
  "acceptContract": false
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/consents/contract",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "acceptTerms": False,
        "acceptPrivacy": False,
        "acceptAml": False,
        "acceptContract": False
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/consents/contract", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "acceptTerms": false,
    "acceptPrivacy": false,
    "acceptAml": false,
    "acceptContract": false
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "termsAcceptanceRequired": true,
  "pending": [
    {
      "document": "terms",
      "version": "texte"
    }
  ],
  "biometric": true
}

Answers and errors

StatusMeaning
200

Consentements à jour.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/consents/terms

Accepter les documents du contrat (ancien nom)

The detailed descriptions of this sheet are written in French.

Ancien nom de POST /v1/me/consents/contract, conservé pour les premières versions des applications : même corps, mêmes cases à cocher par le client, mêmes réponses. Sans case cochée, la réponse est 422 contract_not_accepted (le serveur n'accepte jamais à la place du client). Réponse marquée Deprecation: true.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
acceptTermsbooleanno

Case des Conditions générales, obligatoire si elles sont en attente.

acceptPrivacybooleanno

Case de la Politique de confidentialité, obligatoire si elle est en attente.

acceptAmlbooleanno

Case de la Politique LBC/FT, obligatoire si elle est en attente.

acceptContractbooleanno

Case du contrat d'utilisation, obligatoire seulement s'il est seul en attente.

Request example

{
  "acceptTerms": false,
  "acceptPrivacy": false,
  "acceptAml": false,
  "acceptContract": false
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/consents/terms" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "acceptTerms": false,
  "acceptPrivacy": false,
  "acceptAml": false,
  "acceptContract": false
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/consents/terms');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "acceptTerms": false,
  "acceptPrivacy": false,
  "acceptAml": false,
  "acceptContract": false
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/consents/terms",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "acceptTerms": False,
        "acceptPrivacy": False,
        "acceptAml": False,
        "acceptContract": False
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/consents/terms", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "acceptTerms": false,
    "acceptPrivacy": false,
    "acceptAml": false,
    "acceptContract": false
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "termsAcceptanceRequired": true,
  "pending": [
    {
      "document": "terms",
      "version": "texte"
    }
  ],
  "biometric": true
}

Answers and errors

StatusMeaning
200

Consentements à jour.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/me/documents

Show the documents I accepted

The detailed descriptions of this sheet are written in French.

Les documents du contrat d'utilisation en vigueur (Conditions générales, Politique de confidentialité, Politique LBC/FT, contrat) avec, pour chacun, la version acceptée par le client, la date et le canal, le contrat accepté avec les versions des trois documents, et les documents dont une nouvelle version attend l'acceptation (POST /v1/me/consents/contract).

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/me/documents" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/documents');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/me/documents",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/documents", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "documents": [
    {
      "document": "terms",
      "title": "texte",
      "version": "texte",
      "draft": true,
      "accepted": {
        "version": "texte",
        "acceptedAt": "2026-10-01T09:30:00Z",
        "channel": "web",
        "agent": true
      },
      "upToDate": true
    }
  ],
  "contract": {
    "version": "texte",
    "acceptedAt": "2026-10-01T09:30:00Z",
    "channel": "web",
    "agent": true,
    "documents": {},
    "upToDate": true,
    "reference": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
  },
  "pending": [
    "terms"
  ]
}

Answers and errors

StatusMeaning
200

Documents et preuves d'acceptation.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

PUT /v1/me/account-mode

Choose the account mode

The detailed descriptions of this sheet are written in French.

wallet conserve un solde chez Linc. pass_through débite directement le mobile money.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
modestringyes

wallet · pass_through

Request example

{
  "mode": "wallet"
}

Code example

curl -X PUT "https://sandbox.api.linc.cd/v1/me/account-mode" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "wallet"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/account-mode');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "mode": "wallet"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.put(
    "https://sandbox.api.linc.cd/v1/me/account-mode",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "mode": "wallet"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/account-mode", {
  method: "PUT",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "mode": "wallet"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "accountMode": "wallet"
}

Answers and errors

StatusMeaning
200

Mode enregistré.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/me/communications

Afficher les choix de communication

The detailed descriptions of this sheet are written in French.

Nouveautés de Linc par e-mail et par SMS, envoyées seulement avec l'accord du client. Les codes, reçus et alertes de sécurité sont toujours envoyés.

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/me/communications" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/communications');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/me/communications",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/communications", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "email": true,
  "sms": true
}

Answers and errors

StatusMeaning
200

Choix en cours.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

PUT /v1/me/communications

Choisir les communications

The detailed descriptions of this sheet are written in French.

Oui ou non pour chaque canal. Chaque choix est conservé comme preuve du consentement.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
emailbooleanyes

Nouveautés par e-mail (à une adresse vérifiée seulement).

smsbooleanyes

Nouveautés par SMS, de 8 h à 20 h (heure de Kinshasa). Répondre STOP les arrête.

Request example

{
  "email": true,
  "sms": true
}

Code example

curl -X PUT "https://sandbox.api.linc.cd/v1/me/communications" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "email": true,
  "sms": true
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/communications');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "email": true,
  "sms": true
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.put(
    "https://sandbox.api.linc.cd/v1/me/communications",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "email": True,
        "sms": True
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/communications", {
  method: "PUT",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "email": true,
    "sms": true
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "email": true,
  "sms": true
}

Answers and errors

StatusMeaning
200

Choix enregistrés.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/me/security/two-factor

Show the two-factor status

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/me/security/two-factor" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/two-factor');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/me/security/two-factor",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/two-factor", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "totp": true,
  "sms": true,
  "backupCodesRemaining": true,
  "availableMethods": [
    "totp"
  ]
}

Answers and errors

StatusMeaning
200

Méthodes actives et méthodes utilisables.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/security/otp

Receive an SMS confirmation code

The detailed descriptions of this sheet are written in French.

Envoie un code SMS pour confirmer une opération sensible. Utilisez le challengeId retourné dans twoFactor.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
purposestringyes

security_change · transfer · payment · withdrawal · card_reveal · card_management · card_add · beneficiary_add

Request example

{
  "purpose": "security_change"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/security/otp" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "purpose": "security_change"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/otp');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "purpose": "security_change"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/security/otp",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "purpose": "security_change"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/otp", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "purpose": "security_change"
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "purpose": "phone_verification",
  "sentTo": "texte",
  "expiresAt": "2026-10-01T09:30:00Z",
  "remainingAttempts": 0
}

Answers and errors

StatusMeaning
201

Code envoyé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/security/password

Change the password

The detailed descriptions of this sheet are written in French.

Exige le mot de passe actuel et un second facteur. Les autres sessions sont fermées.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
currentPasswordstringyes
newPasswordstringyes
twoFactorobjectyes

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringyes

totp · sms · backup_code

twoFactor.codestringyes
twoFactor.challengeIdstring (uuid)no

Request example

{
  "currentPassword": "••••••••",
  "newPassword": "••••••••",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/security/password" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "currentPassword": "••••••••",
  "newPassword": "••••••••",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/password');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "currentPassword": "••••••••",
  "newPassword": "••••••••",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/security/password",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "currentPassword": "••••••••",
        "newPassword": "••••••••",
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/password", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "currentPassword": "••••••••",
    "newPassword": "••••••••",
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 204

Mot de passe changé.

Answers and errors

StatusMeaning
204

Mot de passe changé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/security/totp/setup

Start the TOTP setup

The detailed descriptions of this sheet are written in French.

Retourne le secret et l'URI otpauth:// à afficher en QR code. Second facteur requis.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/security/totp/setup" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/totp/setup');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/security/totp/setup",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/totp/setup", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "secret": "••••••••",
  "uri": "texte"
}

Answers and errors

StatusMeaning
201

Secret généré, en attente de confirmation.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/security/totp/confirm

Confirm the TOTP setup

The detailed descriptions of this sheet are written in French.

Valide un premier code de l'application. Retourne les codes de secours, affichés une seule fois.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
codestringyes

Code à 6 chiffres de l'application d'authentification.

Request example

{
  "code": "••••••"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/security/totp/confirm" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "••••••"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/totp/confirm');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "code": "••••••"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/security/totp/confirm",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "code": "••••••"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/totp/confirm", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "code": "••••••"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "backupCodes": [
    "123456"
  ]
}

Answers and errors

StatusMeaning
200

TOTP activé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/security/totp/disable

Turn TOTP off

The detailed descriptions of this sheet are written in French.

Second facteur requis.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/security/totp/disable" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/totp/disable');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/security/totp/disable",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/totp/disable", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 204

TOTP désactivé.

Answers and errors

StatusMeaning
204

TOTP désactivé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

PUT /v1/me/security/sms

Turn SMS two-factor on or off

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
enabledbooleanyes
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "enabled": true
}

Code example

curl -X PUT "https://sandbox.api.linc.cd/v1/me/security/sms" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": true
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/sms');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "enabled": true
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.put(
    "https://sandbox.api.linc.cd/v1/me/security/sms",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "enabled": True
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/sms", {
  method: "PUT",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "enabled": true
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "totp": true,
  "sms": true,
  "backupCodesRemaining": true
}

Answers and errors

StatusMeaning
200

Nouvel état de la double authentification.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/me/security/backup-codes

Regenerate the backup codes

The detailed descriptions of this sheet are written in French.

Invalide les anciens codes. TOTP actif et second facteur requis.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/me/security/backup-codes" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/security/backup-codes');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/me/security/backup-codes",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/security/backup-codes", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "backupCodes": [
    "123456"
  ]
}

Answers and errors

StatusMeaning
200

Nouveaux codes, affichés une seule fois.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/kyc/cases

Open a KYC case

The detailed descriptions of this sheet are written in French.

Ouvre un dossier pour le niveau 2 (identité vérifiée) ou 3 (vigilance renforcée).

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

Request body

NameTypeRequiredDescription
targetLevelintegeryes

2 · 3

documentTypestringno

voter_card · passport · driving_license · national_id

documentNumberstringno
issuingCountrystringno
residenceCountrystringno

Pays de résidence (ISO 3166 alpha-2), niveau 2. Une fois le dossier approuvé, il remplace l'indicatif du téléphone pour les services ouverts par pays.

birthDatestring (date)no
addressstringno
occupationstringno
sourceOfFundsstringno
expectedMonthlyAmountstringno

Montant mensuel attendu en USD (décimal en texte), par exemple 1500.00.

documentExpiresOnstring (date)no

Date d'expiration imprimée sur la pièce (niveau 2). Aucune lecture automatique en mode manual_review ; une pièce expirée est refusée.

nationalitystringno

Nationalité (ISO 3166 alpha-2), niveau 2. Par défaut, le pays qui a délivré la pièce.

residencePermitNumberstringno

Numéro du titre de séjour (carte de résident). Exigé quand la nationalité ou la pièce n'est pas celle du pays de résidence (étranger résidant) : requiredDocuments comprend alors son recto et son verso, et la conformité vérifie le dossier.

residencePermitExpiresOnstring (date)no

Date d'expiration du titre de séjour ; son renouvellement suit celui de la pièce.

Request example

{
  "targetLevel": 2
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/kyc/cases" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "targetLevel": 2
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/kyc/cases');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "targetLevel": 2
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/kyc/cases",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "targetLevel": 2
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/kyc/cases", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "targetLevel": 2
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "reference": "LP-7K2Q4F",
  "targetLevel": 2,
  "status": "draft",
  "message": "texte",
  "requiredDocuments": [
    "id_front"
  ],
  "optionalDocuments": [
    "id_front"
  ],
  "uploadedDocuments": [
    "id_front"
  ],
  "livenessChallenges": [
    {
      "code": "turn_left",
      "instruction": "texte"
    }
  ],
  "captureSteps": [
    {
      "kind": "id_front",
      "challenge": "turn_left",
      "label": "texte",
      "done": true
    }
  ],
  "documentExpiresOn": "1990-01-31",
  "reviewHours": 0,
  "submittedAt": "2026-10-01T09:30:00Z",
  "decidedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
201

Dossier ouvert.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/kyc/cases/current

Show my current KYC case

The detailed descriptions of this sheet are written in French.

Niveau actuel et dernier dossier. Interrogez cette route pour suivre la décision.

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/kyc/cases/current" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/kyc/cases/current');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/kyc/cases/current",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/kyc/cases/current", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "kycLevel": 1,
  "case": {
    "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "reference": "LP-7K2Q4F",
    "targetLevel": 2,
    "status": "draft",
    "message": "texte",
    "requiredDocuments": [
      "id_front"
    ],
    "optionalDocuments": [
      "id_front"
    ],
    "uploadedDocuments": [
      "id_front"
    ],
    "livenessChallenges": [
      {
        "code": "turn_left",
        "instruction": "texte"
      }
    ],
    "captureSteps": [
      {
        "kind": "id_front",
        "challenge": "turn_left",
        "label": "texte",
        "done": true
      }
    ],
    "documentExpiresOn": "1990-01-31",
    "reviewHours": 0,
    "submittedAt": "2026-10-01T09:30:00Z",
    "decidedAt": "2026-10-01T09:30:00Z"
  }
}

Answers and errors

StatusMeaning
200

Niveau KYC et dossier (ou null).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/kyc/cases/{id}/documents/{kind}

Add a document to the KYC case

The detailed descriptions of this sheet are written in French.

Envoie une photo dans le champ multipart file (capture guidée). Au niveau 2, la pièce et le visage viennent de la caméra (captureSource=camera) : un fichier choisi est refusé (kyc_camera_required). Chaque image du vivant indique sa consigne (challenge). Taille minimale (côté long) : 1000 px pour la pièce, 480 px pour le visage (kyc_image_too_small). Le selfie et les images du vivant exigent le consentement biométrique.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant du dossier.

kindpathstringyes

Type de document.

Request body

File sent as multipart/form-data.

NameTypeRequiredDescription
filestringyes

Photo du document (JPEG, PNG ou PDF).

captureSourcestringno

Origine de l'image ; camera obligatoire pour la pièce et le visage au niveau 2.

camera · handoff · upload

challengestringno

Consigne du contrôle du vivant actif.

turn_left · turn_right · blink · smile · look_up

brightnessintegerno

Luminosité moyenne mesurée par l'application avant l'envoi.

sharpnessintegerno

Netteté mesurée par l'application (variance du laplacien).

glareintegerno

Part de pixels brûlés (reflet), en millièmes.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/documents/id_front" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -F "file=@document.jpg"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/documents/id_front');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_POSTFIELDS => ['file' => new CURLFile('document.jpg')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/documents/id_front",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    files={"file": open("document.jpg", "rb")},
    timeout=30,
)
print(answer.status_code, answer.text)
import { openAsBlob } from "node:fs";

const form = new FormData();
form.append("file", await openAsBlob("document.jpg"), "document.jpg");

const answer = await fetch("https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/documents/id_front", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
  body: form,
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "document": {
    "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "kind": "id_front",
    "size": 0
  },
  "case": {
    "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "reference": "LP-7K2Q4F",
    "targetLevel": 2,
    "status": "draft",
    "message": "texte",
    "requiredDocuments": [
      "id_front"
    ],
    "optionalDocuments": [
      "id_front"
    ],
    "uploadedDocuments": [
      "id_front"
    ],
    "livenessChallenges": [
      {
        "code": "turn_left",
        "instruction": "texte"
      }
    ],
    "captureSteps": [
      {
        "kind": "id_front",
        "challenge": "turn_left",
        "label": "texte",
        "done": true
      }
    ],
    "documentExpiresOn": "1990-01-31",
    "reviewHours": 0,
    "submittedAt": "2026-10-01T09:30:00Z",
    "decidedAt": "2026-10-01T09:30:00Z"
  }
}

Answers and errors

StatusMeaning
201

Document ajouté.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/kyc/cases/{id}/submit

Submit the KYC case

The detailed descriptions of this sheet are written in French.

Lance la vérification. Le résultat arrive de façon asynchrone (SMS et GET /v1/kyc/cases/current).

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant du dossier.

Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/submit" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/submit');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16))],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/submit",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/kyc/cases/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/submit", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID() },
});
console.log(answer.status, await answer.text());

Answer example 202

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "reference": "LP-7K2Q4F",
  "targetLevel": 2,
  "status": "draft",
  "message": "texte",
  "requiredDocuments": [
    "id_front"
  ],
  "optionalDocuments": [
    "id_front"
  ],
  "uploadedDocuments": [
    "id_front"
  ],
  "livenessChallenges": [
    {
      "code": "turn_left",
      "instruction": "texte"
    }
  ],
  "captureSteps": [
    {
      "kind": "id_front",
      "challenge": "turn_left",
      "label": "texte",
      "done": true
    }
  ],
  "documentExpiresOn": "1990-01-31",
  "reviewHours": 0,
  "submittedAt": "2026-10-01T09:30:00Z",
  "decidedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
202

Dossier envoyé, vérification en cours.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/corridors

List the open corridors

The detailed descriptions of this sheet are written in French.

Pays de destination, devises et modes de réception ouverts (public). Un pays fermé, ou dont tous les corridors sont fermés, n'apparaît pas ; un corridor fermé (mode de réception d'un pays) n'est pas dans payoutMethods (« Partenaires › Pays et corridors », docs/adr/0068). Les devis suivent aussitôt.

Authentication: None (public route)

Code example

curl "https://sandbox.api.linc.cd/v1/corridors"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/corridors');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/corridors",
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/corridors", {
  method: "GET",
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "corridors": [
    {
      "country": "CI",
      "name": "Côte d’Ivoire",
      "currency": "XOF",
      "currencies": [
        "XOF"
      ],
      "payoutMethods": [
        "mobile_money",
        "bank_account",
        "card"
      ]
    },
    {
      "country": "CA",
      "name": "Canada",
      "currency": "CAD",
      "currencies": [
        "CAD",
        "USD"
      ],
      "payoutMethods": [
        "bank_account",
        "card"
      ]
    }
  ]
}

Answers and errors

StatusMeaning
200

Corridors ouverts.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/journeys

List the journeys open to the customer

The detailed descriptions of this sheet are written in French.

Parcours de paiement (source → destination) ouverts pour le client authentifié vers un pays, et une devise de réception si elle est donnée (« Partenaires › Parcours », docs/adr/0083). Seuls ces parcours sont à proposer : ils tiennent compte de l'état du parcours, du pays, du niveau KYC, de la population (liste pilote, segment) et du mode de compte. Les autres verrous (corridors, partenaires) restent ceux de listCorridors et du devis ; chaque devis, envoi et paiement revérifie le parcours et refuse sinon avec operation_unavailable.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
countryquerystringyes

Pays de destination (le pays du marchand pour un paiement, CD pour le solde).

currencyquerystringno

Devise reçue ; absente, toute devise.

Code example

curl "https://sandbox.api.linc.cd/v1/journeys?country=KE" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/journeys?country=KE');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/journeys?country=KE",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/journeys?country=KE", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "country": "KE",
  "currency": "USD",
  "journeys": [
    {
      "source": "card_visa_aft",
      "destination": "card_visa"
    }
  ]
}

Answers and errors

StatusMeaning
200

Parcours ouverts pour ce client.

422

journey_query_invalid : country n'est pas un code pays ISO à deux lettres, ou currency n'est pas une devise connue de Linc.

Error as application/problem+json: see “Errors”.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/quotes

Ask for a quote

The detailed descriptions of this sheet are written in French.

Frais, taux, total débité et montant reçu, verrouillés 60 s. Au plus 20 devis par minute et par client (renouvellements compris) : au-delà, 429 too_many_quotes.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

Request body

NameTypeRequiredDescription
amountstringno

Montant envoyé en décimal (texte), par exemple 150.00. Ancien nom de sendAmount.

sendAmountstringno

Montant envoyé en décimal (texte), par exemple 150.00.

receiveAmountstringno

Montant à recevoir dans la devise reçue, avec ses décimales (XOF 0, KWD 3), par exemple 50000.

totalAmountstringno

Total payé par le client dans la devise envoyée, frais déduits, par exemple 100.00.

operatorstringno

Facultatif (mobile_money) : opérateur du wallet du bénéficiaire, son nom ou son code (operators de GET /v1/reference/destination-formats). La ligne de la grille du partenaire pour cet opérateur s'applique au devis. Inconnu : ignoré.

msisdnstringno

Facultatif (mobile_money) : numéro du bénéficiaire, l'opérateur est déduit de son préfixe quand operator est absent.

currencystringyes

Code devise ISO 4217.

destinationCountrystringyes
payoutMethodstringyes

cash_pickup : retrait d'espèces avec un code dans le réseau Mastercard, là où il est ouvert (bénéficiaire : nom exactement comme sur sa pièce et téléphone).

mobile_money · bank_account · card · cash_pickup

receiveCurrencystringno

Une des devises du corridor. Vide = devise principale du corridor.

sourceTypestringno

Source des fonds. card (carte bancaire, AFT) a ses propres frais ; le devis ne sert alors qu'à un envoi par carte. card_interswitch : carte sur la page de paiement Interswitch, frais propres, parcours fermé par défaut.

· mobile_money · wallet · card · card_interswitch

Request example

{
  "amount": "150.00",
  "currency": "USD",
  "destinationCountry": "CI",
  "payoutMethod": "mobile_money",
  "sourceType": "mobile_money"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/quotes" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": "150.00",
  "currency": "USD",
  "destinationCountry": "CI",
  "payoutMethod": "mobile_money",
  "sourceType": "mobile_money"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/quotes');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "amount": "150.00",
  "currency": "USD",
  "destinationCountry": "CI",
  "payoutMethod": "mobile_money",
  "sourceType": "mobile_money"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/quotes",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "amount": "150.00",
        "currency": "USD",
        "destinationCountry": "CI",
        "payoutMethod": "mobile_money",
        "sourceType": "mobile_money"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/quotes", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "amount": "150.00",
    "currency": "USD",
    "destinationCountry": "CI",
    "payoutMethod": "mobile_money",
    "sourceType": "mobile_money"
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "id": "0192a7c4-5b1e-7c3a-9f10-3d2e8b6a4c11",
  "send": {
    "amount": 15000,
    "currency": "USD",
    "display": "150,00 $"
  },
  "fee": {
    "amount": 325,
    "currency": "USD",
    "display": "3,25 $"
  },
  "vat": {
    "amount": 52,
    "currency": "USD",
    "display": "0,52 $"
  },
  "levy": {
    "amount": 30,
    "currency": "USD",
    "display": "0,30 $"
  },
  "total": {
    "amount": 15407,
    "currency": "USD",
    "display": "154,07 $"
  },
  "receive": {
    "amount": 84900,
    "currency": "XOF",
    "display": "84 900 FCFA"
  },
  "rate": "566.00",
  "destinationCountry": "CI",
  "payoutMethod": "mobile_money",
  "createdAt": "2026-09-29T14:00:00+00:00",
  "expiresAt": "2026-09-29T14:01:00+00:00",
  "consumed": false,
  "sourceType": null
}

Answers and errors

StatusMeaning
201

Devis créé.

422

Refus métier (Problem.code), dont journey_limit_exceeded : le montant dépasse un plafond du parcours de paiement (par envoi, par jour ou par mois, en USD quelle que soit la devise envoyée, docs/adr/0083). detail donne le plafond atteint (« 30.00 USD »). Un parcours fermé répond operation_unavailable (403), sans motif.

Error as application/problem+json: see “Errors”.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/quotes/preview

Aperçu du prix pendant la saisie

The detailed descriptions of this sheet are written in French.

Prix indicatif dans tous les sens : sendAmount (ou amount), receiveAmount ou totalAmount (« frais déduits », là où le corridor l'offre) — deux ou aucun → 422 amount_ambiguous. Un total qui ne couvre pas les frais → 422 total_below_fees ; un prix à perte → 422 margin_too_low. Rien n'est enregistré, aucun taux n'est verrouillé ; les plafonds du client sont vérifiés pour le dire tout de suite. Le devis (POST /v1/quotes) est demandé quand le client continue. Plus de 12 chiffres avant la virgule, ou un montant trop grand pour être calculé → 422 amount_too_large.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
destinationCountryquerystringyes
payoutMethodquerystringyes
currencyquerystringno

Devise envoyée (USD par défaut).

sendAmountquerystringno
amountquerystringno

Ancien nom de sendAmount.

receiveAmountquerystringno
totalAmountquerystringno

Total payé par le client dans la devise envoyée

receiveCurrencyquerystringno
sourceTypequerystringno
operatorquerystringno

Opérateur du wallet du bénéficiaire (nom ou code), pour sa ligne de la grille du partenaire.

msisdnquerystringno

Numéro du bénéficiaire : opérateur déduit du préfixe sans operator.

Code example

curl "https://sandbox.api.linc.cd/v1/quotes/preview?destinationCountry=KE&payoutMethod=mobile_money" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/quotes/preview?destinationCountry=KE&payoutMethod=mobile_money');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/quotes/preview?destinationCountry=KE&payoutMethod=mobile_money",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/quotes/preview?destinationCountry=KE&payoutMethod=mobile_money", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "typed": "send",
  "send": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "fee": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "vat": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "levy": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "total": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "receive": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "rate": "texte"
}

Answers and errors

StatusMeaning
200

Prix indicatif.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/quotes/{id}

Show a quote

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant du devis.

Code example

curl "https://sandbox.api.linc.cd/v1/quotes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/quotes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/quotes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/quotes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "send": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "fee": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "vat": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "levy": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "total": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "receive": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "rate": "texte",
  "destinationCountry": "KE",
  "payoutMethod": "mobile_money",
  "createdAt": "2026-10-01T09:30:00Z",
  "expiresAt": "2026-10-01T09:30:00Z",
  "consumed": true,
  "sourceType": "card"
}

Answers and errors

StatusMeaning
200

Devis.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/reference/banks

Chercher une banque du pays pendant la frappe

The detailed descriptions of this sheet are written in French.

Banques du référentiel du pays, cherchées par nom, sigle, BIC ou code national (sort code, code banque) ; au plus 20, une par banque, à partir de 2 caractères (liste vide avant). « Autre banque » reste possible : nom et BIC saisis. Public, limité par adresse (429 au-delà).

Authentication: None (public route)

Parameters

NameInTypeRequiredDescription
countryquerystringyes

Pays de la banque (ISO 3166-1 alpha-2).

qquerystringno

Début ou partie du nom, du sigle, du BIC ou du code de la banque ; 2 caractères au moins.

Code example

curl "https://sandbox.api.linc.cd/v1/reference/banks?country=KE"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/reference/banks?country=KE');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/reference/banks?country=KE",
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/reference/banks?country=KE", {
  method: "GET",
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "banks": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "name": "texte"
    }
  ]
}

Answers and errors

StatusMeaning
200

Banques trouvées (vide pour un pays inconnu).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/reference/destination-formats

Formats de destination d'un pays

The detailed descriptions of this sheet are written in French.

Opérateurs de mobile money avec les préfixes et longueurs de leurs numéros (l'opérateur est détecté d'après le numéro : un seul possible → présélectionné, plusieurs → proposés en premier, aucun → message) et longueur de l'IBAN du pays (registre officiel) pour dire exactement ce qui manque, et schémas de compte du pays (IBAN, RIB, sort code…, le schéma par défaut en premier) avec leurs champs : l'application affiche les champs du schéma choisi et envoie scheme avec eux. Le serveur revérifie tout à l'enregistrement du bénéficiaire. Public, limité par adresse (429 au-delà).

Authentication: None (public route)

Parameters

NameInTypeRequiredDescription
countryquerystringyes

Pays du bénéficiaire (ISO 3166-1 alpha-2).

Code example

curl "https://sandbox.api.linc.cd/v1/reference/destination-formats?country=KE"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/reference/destination-formats?country=KE');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/reference/destination-formats?country=KE",
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/reference/destination-formats?country=KE", {
  method: "GET",
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "country": "KE",
  "name": "texte",
  "operators": [
    {
      "code": "mpesa",
      "name": "M-Pesa",
      "prefixes": [
        "texte"
      ],
      "lengths": [
        0
      ]
    }
  ],
  "accountSchemes": [
    {
      "code": "rib",
      "label": "RIB (UEMOA)",
      "fields": [
        {
          "detail": "accountNumber",
          "label": "texte",
          "required": true,
          "maxLength": 0,
          "numeric": true,
          "iban": true,
          "choices": []
        }
      ]
    }
  ]
}

Answers and errors

StatusMeaning
200

Formats du pays (listes vides pour un pays inconnu).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/beneficiaries

List my beneficiaries

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/beneficiaries" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/beneficiaries');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/beneficiaries",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/beneficiaries", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "beneficiaries": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "fullName": "texte",
      "country": "KE",
      "payoutMethod": "mobile_money",
      "destination": "texte"
    }
  ]
}

Answers and errors

StatusMeaning
200

Bénéficiaires enregistrés.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/beneficiaries

Add a beneficiary

The detailed descriptions of this sheet are written in French.

Les coordonnées complètes restent chez Linc. La réponse les affiche masquées. Selon les contrôles de sécurité de l'opération, la réponse peut être two_factor_required : redemandez avec twoFactor (code de l'application d'authentification, ou code SMS obtenu par POST /v1/me/security/otp avec purpose = beneficiary_add). Une opération qui ne peut pas aboutir répond operation_unavailable (403), sans motif : ce code est commun à plusieurs refus.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
fullNamestringyes
countrystringyes
payoutMethodstringyes

cash_pickup : retrait d'espèces avec un code dans le réseau Mastercard, là où il est ouvert (bénéficiaire : nom exactement comme sur sa pièce et téléphone).

mobile_money · bank_account · card · cash_pickup

detailsobjectno

Coordonnées selon le mode (msisdn, provider, bankName, accountNumber, bankCode, cardToken…). Compte bancaire : de préférence scheme (code d'un schéma de GET /v1/reference/destination-formats) et les champs de ce schéma (accountNumber pour un RIB, bankCode + accountNumber pour un sort code…), bankId d'une banque de la liste ; sans scheme, iban ou accountNumber comme avant. bankCode (compte bancaire, facultatif) : sort code (Royaume-Uni, 6 chiffres), ABA (États-Unis, 9 chiffres) ou code banque ou guichet (3 à 15 lettres ou chiffres) ; espaces et tirets ignorés. Facultatif pour tous les modes : relationship (lien avec l'expéditeur : family, friend, self, business, other), exigé par certains corridors.

twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "fullName": "Bastian Kelyan",
  "country": "CI",
  "payoutMethod": "mobile_money",
  "details": {
    "msisdn": "+2250700000000",
    "provider": "orange",
    "relationship": "family"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/beneficiaries" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "fullName": "Bastian Kelyan",
  "country": "CI",
  "payoutMethod": "mobile_money",
  "details": {
    "msisdn": "+2250700000000",
    "provider": "orange",
    "relationship": "family"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/beneficiaries');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "fullName": "Bastian Kelyan",
  "country": "CI",
  "payoutMethod": "mobile_money",
  "details": {
    "msisdn": "+2250700000000",
    "provider": "orange",
    "relationship": "family"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/beneficiaries",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "fullName": "Bastian Kelyan",
        "country": "CI",
        "payoutMethod": "mobile_money",
        "details": {
            "msisdn": "+2250700000000",
            "provider": "orange",
            "relationship": "family"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/beneficiaries", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "fullName": "Bastian Kelyan",
    "country": "CI",
    "payoutMethod": "mobile_money",
    "details": {
      "msisdn": "+2250700000000",
      "provider": "orange",
      "relationship": "family"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "id": "0192a7c4-6f02-7a55-8e21-7b4c0d9e2f33",
  "fullName": "Bastian Kelyan",
  "country": "CI",
  "payoutMethod": "mobile_money",
  "destination": "Orange Money •• 0000"
}

Answers and errors

StatusMeaning
201

Bénéficiaire ajouté.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

PATCH /v1/beneficiaries/{id}

Complete the bank code of a beneficiary

The detailed descriptions of this sheet are written in French.

Ajoute le code banque (bankCode) d'un bénéficiaire à compte bancaire enregistré sans lui, quand l'envoi répond corridor_fields_missing avec bank_code. Contrôle selon le pays : sort code au Royaume-Uni (6 chiffres), ABA aux États-Unis (9 chiffres), 3 à 15 lettres ou chiffres ailleurs ; espaces et tirets ignorés. Un code déjà enregistré n'est jamais remplacé (beneficiary_bank_code_set, 409 : une autre banque est un autre bénéficiaire) ; le même code ne change rien. Contrôles de sécurité de l'ajout d'un bénéficiaire : la réponse peut être two_factor_required, redemandez avec twoFactor (purpose = beneficiary_add).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant du bénéficiaire.

Request body

NameTypeRequiredDescription
bankCodestringyes

Sort code (Royaume-Uni), ABA (États-Unis) ou code banque ou guichet.

twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "bankCode": "123456"
}

Code example

curl -X PATCH "https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "bankCode": "123456"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "bankCode": "123456"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.patch(
    "https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "bankCode": "123456"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "PATCH",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "bankCode": "123456"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "fullName": "texte",
  "country": "KE",
  "payoutMethod": "mobile_money",
  "destination": "texte"
}

Answers and errors

StatusMeaning
200

Bénéficiaire complété (coordonnées masquées).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

DELETE /v1/beneficiaries/{id}

Delete a beneficiary

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant du bénéficiaire.

Code example

curl -X DELETE "https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.delete(
    "https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 204

Bénéficiaire supprimé.

Answers and errors

StatusMeaning
204

Bénéficiaire supprimé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/beneficiaries/{id}/purposes

Purposes offered for this beneficiary

The detailed descriptions of this sheet are written in French.

Motifs que le corridor accepte : sur Visa Direct et Mastercard Cross-Border, seuls ceux qui ont un code partenaire pour le pays (rail principal, ou secours s'il prend le relais) ; tous sur les autres rails. Liste vide : ne demandez pas de motif. Avec quoteId, la devise reçue du devis.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant du bénéficiaire.

quoteIdquerystringno

Devis en cours (devise reçue). Par défaut, la devise principale du corridor.

Code example

curl "https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/purposes" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/purposes');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/purposes",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/beneficiaries/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/purposes", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "purposes": [
    {
      "code": "family_support",
      "label": "texte"
    }
  ]
}

Answers and errors

StatusMeaning
200

Motifs proposés, dans l'ordre d'affichage.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/transfers

List my transfers

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/transfers" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/transfers",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "transfers": [
    {
      "reference": "LP-7K2Q4F",
      "status": "in_progress",
      "steps": [
        {
          "label": "texte",
          "done": true
        }
      ],
      "beneficiary": "texte",
      "destination": "texte",
      "country": "KE",
      "source": "texte",
      "sourceType": "mobile_money",
      "send": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "fee": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "vat": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "levy": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "total": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "receive": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "rate": "texte",
      "createdAt": "2026-10-01T09:30:00Z",
      "deliveredAt": "2026-10-01T09:30:00Z",
      "refundedAt": "2026-10-01T09:30:00Z"
    }
  ]
}

Answers and errors

StatusMeaning
200

Envois du client, du plus récent au plus ancien.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/transfers

Send money

The detailed descriptions of this sheet are written in French.

Confirme un devis vers un bénéficiaire. Second facteur requis. Le traitement est asynchrone (suivez les étapes). Un client dont le pays de résidence n'est pas un pays d'origine autorisé est refusé (origin_not_allowed, 403) avant tout prélèvement ; la conformité est alertée.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
quoteIdstring (uuid)yes
beneficiaryIdstring (uuid)yes
sourceobjectyes
source.typestringyes

wallet : mode wallet uniquement. card : carte bancaire du client (KYC niveau 2), payée ensuite sur la page carte (GET /v1/transfers/{reference}/card-checkout) avec 3-D Secure ; le devis doit être un devis carte. card_interswitch : carte (ou mobile money) payée sur la page d'Interswitch (Web Checkout), option fermée par défaut et ouverte parcours par parcours ; KYC niveau 2, devis sourceType=card_interswitch, puis GET /v1/transfers/{reference}/checkout.

mobile_money · wallet · card · card_interswitch

source.providerstringno

airtel · mpesa · orange · afrimoney

source.msisdnstringno
source.savedWalletIdstring (uuid)no

Source mobile_money : porte-monnaie enregistré vérifié (GET /v1/saved-wallets) ; opérateur et numéro en sont lus, provider et msisdn sont ignorés. Refusé (saved_wallet_not_verified, saved_wallet_not_found) s'il n'est pas au client ou pas vérifié.

source.savedCardIdstring (uuid)no

Source card : carte enregistrée choisie dans le devis (GET /v1/saved-cards), proposée sur la page carte sans ressaisie.

purposestringno

Motif de l'envoi déclaré par le client, parmi ceux de GET /v1/beneficiaries/{id}/purposes (sinon transfer_purpose_not_offered). Facultatif quand la liste est vide ; un corridor qui exige un motif refuse la création sans lui (corridor_fields_missing).

family_support · education · medical · gift · savings · bills · business · salary · goods_services · other

twoFactorobjectyes

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringyes

totp · sms · backup_code

twoFactor.codestringyes
twoFactor.challengeIdstring (uuid)no

Request example

{
  "quoteId": "0192a7c4-5b1e-7c3a-9f10-3d2e8b6a4c11",
  "beneficiaryId": "0192a7c4-6f02-7a55-8e21-7b4c0d9e2f33",
  "source": {
    "type": "mobile_money",
    "provider": "airtel",
    "msisdn": "+243970000000"
  },
  "purpose": "family_support",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/transfers" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "quoteId": "0192a7c4-5b1e-7c3a-9f10-3d2e8b6a4c11",
  "beneficiaryId": "0192a7c4-6f02-7a55-8e21-7b4c0d9e2f33",
  "source": {
    "type": "mobile_money",
    "provider": "airtel",
    "msisdn": "+243970000000"
  },
  "purpose": "family_support",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "quoteId": "0192a7c4-5b1e-7c3a-9f10-3d2e8b6a4c11",
  "beneficiaryId": "0192a7c4-6f02-7a55-8e21-7b4c0d9e2f33",
  "source": {
    "type": "mobile_money",
    "provider": "airtel",
    "msisdn": "+243970000000"
  },
  "purpose": "family_support",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/transfers",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "quoteId": "0192a7c4-5b1e-7c3a-9f10-3d2e8b6a4c11",
        "beneficiaryId": "0192a7c4-6f02-7a55-8e21-7b4c0d9e2f33",
        "source": {
            "type": "mobile_money",
            "provider": "airtel",
            "msisdn": "+243970000000"
        },
        "purpose": "family_support",
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "quoteId": "0192a7c4-5b1e-7c3a-9f10-3d2e8b6a4c11",
    "beneficiaryId": "0192a7c4-6f02-7a55-8e21-7b4c0d9e2f33",
    "source": {
      "type": "mobile_money",
      "provider": "airtel",
      "msisdn": "+243970000000"
    },
    "purpose": "family_support",
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 202

{
  "reference": "LP-8QK2ZD",
  "status": "in_progress",
  "steps": [
    {
      "label": "Envoi initié",
      "done": true
    },
    {
      "label": "Fonds prélevés sur votre mobile money",
      "done": false
    },
    {
      "label": "Versement au bénéficiaire en cours",
      "done": false
    },
    {
      "label": "Fonds reçus par le bénéficiaire",
      "done": false
    }
  ],
  "beneficiary": "Bastian Kelyan",
  "destination": "Orange Money •• 0000",
  "country": "CI",
  "source": "Airtel Money •• 0000",
  "sourceType": "mobile_money",
  "send": {
    "amount": 15000,
    "currency": "USD",
    "display": "150,00 $"
  },
  "fee": {
    "amount": 325,
    "currency": "USD",
    "display": "3,25 $"
  },
  "vat": {
    "amount": 52,
    "currency": "USD",
    "display": "0,52 $"
  },
  "levy": {
    "amount": 30,
    "currency": "USD",
    "display": "0,30 $"
  },
  "total": {
    "amount": 15407,
    "currency": "USD",
    "display": "154,07 $"
  },
  "receive": {
    "amount": 84900,
    "currency": "XOF",
    "display": "84 900 FCFA"
  },
  "rate": "566.00",
  "createdAt": "2026-09-29T14:00:20+00:00",
  "deliveredAt": null,
  "refundedAt": null
}

Answers and errors

StatusMeaning
202

Envoi accepté, en cours de traitement.

422

Refus métier (Problem.code), dont journey_limit_exceeded : le montant dépasse un plafond du parcours de paiement (par envoi, par jour ou par mois, en USD quelle que soit la devise envoyée, docs/adr/0083). detail donne le plafond atteint (« 30.00 USD »). Un parcours fermé répond operation_unavailable (403), sans motif.

Error as application/problem+json: see “Errors”.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/transfers/{reference}/repeat

Renvoyer un transfert (valeurs pré-remplies)

The detailed descriptions of this sheet are written in French.

« Renvoyer » : bénéficiaire, moyen de paiement, destination et montant d'un transfert terminé (livré, remboursé ou échoué), pour remplir l'écran d'envoi. Aucune écriture : l'envoi demande un nouveau devis (jamais l'ancien taux), puis suit le parcours normal (2FA, nouvelle clé d'idempotence, filtrage AML, plafonds, parcours ouvert). Bénéficiaire supprimé, corridor ou parcours fermé : complete à faux, beneficiaryId nul et issue dit quoi choisir. Transfert en cours (y compris un remboursement pas encore terminé) : 409 transfer_in_progress ; référence d'un autre client : 404 transfer_not_found. Le solde n'est repris que si le compte est en mode wallet, le motif que s'il est encore proposé pour ce bénéficiaire.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Code example

curl "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/repeat" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/repeat');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/repeat",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/repeat", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "beneficiaryId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "beneficiaryName": "texte",
  "country": "KE",
  "payoutMethod": "mobile_money",
  "sendAmount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "receiveCurrency": "USD",
  "complete": true,
  "issue": {
    "code": "beneficiary_deleted",
    "message": "texte"
  }
}

Answers and errors

StatusMeaning
200

Valeurs de l'écran d'envoi.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/transfers/{reference}

Track a transfer

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de l'envoi.

Code example

curl "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "status": "in_progress",
  "steps": [
    {
      "label": "texte",
      "done": true
    }
  ],
  "beneficiary": "texte",
  "destination": "texte",
  "country": "KE",
  "source": "texte",
  "sourceType": "mobile_money",
  "send": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "fee": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "vat": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "levy": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "total": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "receive": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "rate": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "deliveredAt": "2026-10-01T09:30:00Z",
  "refundedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Envoi et étapes de suivi.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/transfers/{reference}/cash-pickup/code

Afficher le code de retrait

The detailed descriptions of this sheet are written in French.

Retrait d'espèces : le code à donner au bénéficiaire, après un second facteur ; jamais mis en cache, jamais renvoyé par le support. 409 cash_pickup_not_pending une fois retiré, annulé ou remboursé.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de l'envoi.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/code" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/code');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/code",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/code", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "code": "••••••"
}

Answers and errors

StatusMeaning
200

Code de retrait.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/transfers/{reference}/cash-pickup/sms

Renvoyer le code au bénéficiaire par SMS

The detailed descriptions of this sheet are written in French.

Au plus 3 renvois par envoi (429 cash_pickup_resend_limit au-delà) ; chaque envoi est journalisé.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de l'envoi.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/sms" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/sms');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/sms",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/sms", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "sent": true,
  "cashPickup": {
    "status": "pending",
    "expiresAt": "2026-10-01T09:30:00Z",
    "smsUndelivered": true,
    "resendsLeft": 0,
    "amendmentsLeft": 0,
    "nameUnderReview": true,
    "cancelledBy": "expired",
    "refundable": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "refundIfCancelled": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    }
  }
}

Answers and errors

StatusMeaning
200

SMS parti ou non (sent) et état du retrait.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/transfers/{reference}/cash-pickup/cancel

Annuler un retrait d'espèces

The detailed descriptions of this sheet are written in French.

Tant que l'argent n'est pas retiré, après un second facteur : Mastercard annule le paiement, puis le montant envoyé est remboursé (frais et marge de change conservés). 409 cash_pickup_cancel_refused si l'argent est déjà retiré : rien n'est remboursé.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de l'envoi.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/cancel" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/cancel');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/cancel",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/cancel", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "outcome": "cancelled",
  "transfer": {
    "reference": "LP-7K2Q4F",
    "status": "in_progress",
    "steps": [
      {
        "label": "texte",
        "done": true
      }
    ],
    "beneficiary": "texte",
    "destination": "texte",
    "country": "KE",
    "source": "texte",
    "sourceType": "mobile_money",
    "send": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "fee": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "vat": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "levy": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "total": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "receive": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "rate": "texte",
    "createdAt": "2026-10-01T09:30:00Z",
    "deliveredAt": "2026-10-01T09:30:00Z",
    "refundedAt": "2026-10-01T09:30:00Z"
  }
}

Answers and errors

StatusMeaning
200

Issue de l'annulation et envoi à jour.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/transfers/{reference}/cash-pickup/name

Corriger le nom du bénéficiaire d'un retrait

The detailed descriptions of this sheet are written in French.

Une fois par envoi, avant le retrait, après un second facteur. Une faute de frappe est corrigée chez Mastercard aussitôt (amended: true) ; au-delà, la conformité valide d'abord (amended: false). 409 cash_pickup_amend_limit, 409 cash_pickup_amend_refused (refusée par Mastercard), 503 cash_pickup_amend_unknown (Mastercard n'a pas répondu : le nom n'est pas modifié, les opérations vérifient).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de l'envoi.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
namestringyes

Nom complet du bénéficiaire, exactement comme sur sa pièce d'identité.

twoFactorobjectyes

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringyes

totp · sms · backup_code

twoFactor.codestringyes
twoFactor.challengeIdstring (uuid)no

Request example

{
  "name": "texte",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/name" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "texte",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/name');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "name": "texte",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/name",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "name": "texte",
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/cash-pickup/name", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "name": "texte",
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "amended": true
}

Answers and errors

StatusMeaning
200

Corrigé ou en attente de la conformité.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/transfers/{reference}/card-checkout

Open the card page of a transfer

The detailed descriptions of this sheet are written in French.

Envoi financé par carte bancaire : page carte, ouverte une fois la vérification de l'envoi passée. Chaque appel donne un nouveau lien à usage unique. 409 card_checkout_not_ready pendant la vérification (réessayez), ou card_payment_closed une fois le paiement par carte terminé.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de l'envoi.

Code example

curl "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/card-checkout" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/card-checkout');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/card-checkout",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/card-checkout", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "status": "pending",
  "url": "https://example.com",
  "expiresAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Page carte à ouvrir.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/transfers/{reference}/checkout

Ouvrir la page de paiement Interswitch d'un envoi

The detailed descriptions of this sheet are written in French.

Envoi payé sur la page de paiement d'Interswitch (Web Checkout) : lien signé qui ouvre cette page dans la vue web de l'application. Le client y choisit son moyen de paiement puis revient par linc-client://envoi/retour ; la redirection ne prouve rien, suivez l'envoi avec GET /v1/transfers/{reference} (la collecte est confirmée de serveur à serveur). 409 checkout_not_ready pendant la vérification de l'envoi (réessayez), checkout_unavailable quand aucun paiement n'attend le client sur cette page (envoi payé autrement, ou déjà confirmé).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de l'envoi.

Code example

curl "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/checkout" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/checkout');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/checkout",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/checkout", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "url": "https://example.com",
  "expiresAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Page de paiement à ouvrir.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/card-payments/{reference}

Track a card payment

The detailed descriptions of this sheet are written in French.

Issue du paiement par carte d'un envoi ou d'un paiement marchand du client (après la page carte).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence du paiement par carte.

Code example

curl "https://sandbox.api.linc.cd/v1/card-payments/LP-7K2Q4F" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/card-payments/LP-7K2Q4F');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/card-payments/LP-7K2Q4F",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/card-payments/LP-7K2Q4F", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "status": "pending",
  "statusLabel": "texte",
  "purpose": "merchant_payment",
  "subject": "texte",
  "amount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "card": "texte",
  "message": "texte",
  "attemptsLeft": 0,
  "expiresAt": "2026-10-01T09:30:00Z",
  "approvedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Paiement par carte.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/saved-cards

List my saved bank cards

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/saved-cards" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-cards');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/saved-cards",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-cards", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "cards": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "label": "texte",
      "network": "visa",
      "last4": "texte",
      "expiry": "texte",
      "issuerCountry": "KE",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "verificationHold": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "verificationNotice": "texte"
}

Answers and errors

StatusMeaning
200

Cartes enregistrées (réseau, 4 derniers chiffres, expiration).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/saved-cards

Add a bank card without paying

The detailed descriptions of this sheet are written in French.

Second facteur requis (purpose card_add), KYC niveau 2. Ouvre la page carte d'une vérification (CV-XXXXXX) : la carte est saisie dans le formulaire hébergé de l'acquéreur, contrôlée comme une carte qui finance un envoi, puis vérifiée par une autorisation de 1 USD (verificationHold de GET /v1/saved-cards, paramétrable) SANS capture, avec 3-D Secure obligatoire. Dès que la banque l'accepte et authentifie le titulaire, l'autorisation est annulée et la carte enregistrée ; rien n'est prélevé. Prévenez le client avant la saisie avec verificationNotice. Suivez l'issue avec GET /v1/card-payments/{reference} (approved puis reversed, ou failed) puis GET /v1/saved-cards. La période d'observation démarre à la vérification.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/saved-cards" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-cards');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/saved-cards",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-cards", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "reference": "LP-7K2Q4F",
  "status": "pending",
  "url": "https://example.com",
  "expiresAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
201

Page carte à ouvrir (lien à usage unique).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

PATCH /v1/saved-cards/{id}

Name a saved card or make it the default one

The detailed descriptions of this sheet are written in French.

nickname : nom donné par le client (40 caractères au plus, vide pour l'effacer) ; default : true en fait la carte proposée en premier au prochain paiement (une seule par client). Un champ absent est laissé tel quel.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte enregistrée.

Request body

NameTypeRequiredDescription
nicknamestringno

Nom donné à la carte ; vide pour l'effacer.

defaultbooleanno

Request example

{
  "nickname": "texte",
  "default": true
}

Code example

curl -X PATCH "https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "nickname": "texte",
  "default": true
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "nickname": "texte",
  "default": true
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.patch(
    "https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "nickname": "texte",
        "default": True
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "PATCH",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "nickname": "texte",
    "default": true
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "label": "texte",
  "network": "visa",
  "last4": "texte",
  "expiry": "texte",
  "issuerCountry": "KE",
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Carte mise à jour.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

DELETE /v1/saved-cards/{id}

Delete a saved bank card

The detailed descriptions of this sheet are written in French.

Le jeton est aussi supprimé chez l'acquéreur.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte enregistrée.

Code example

curl -X DELETE "https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.delete(
    "https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 204

Carte supprimée.

Answers and errors

StatusMeaning
204

Carte supprimée.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/saved-wallets

List my saved mobile money wallets

The detailed descriptions of this sheet are written in French.

Les numéros mobile money enregistrés par le client, le porte-monnaie par défaut en premier. Le numéro n'est jamais renvoyé : opérateur et 4 derniers chiffres seulement. Un porte-monnaie pending n'a pas encore été vérifié : il ne peut pas financer un envoi.

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/saved-wallets" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-wallets');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/saved-wallets",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-wallets", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "wallets": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "label": "texte",
      "provider": "airtel",
      "providerLabel": "texte",
      "last4": "texte",
      "maskedNumber": "texte",
      "status": "pending",
      "verified": true,
      "default": true,
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "max": 0
}

Answers and errors

StatusMeaning
200

Porte-monnaie enregistrés et nombre maximal.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/saved-wallets

Save a mobile money wallet

The detailed descriptions of this sheet are written in French.

Enregistre un numéro mobile money à votre nom. L'opérateur est lu depuis le numéro si provider est absent (saved_wallet_operator_unknown sinon). Le porte-monnaie est pending et un code de 6 chiffres est envoyé par SMS à ce numéro (5 minutes, 5 essais) : renvoyez-le à POST /v1/saved-wallets/{id}/verify avec le challengeId. Le numéro du compte, déjà vérifié, est enregistré verified d'emblée (challengeId nul). Erreurs : saved_wallet_limit (limite atteinte), saved_wallet_exists (déjà enregistré). Le même numéro enregistré par plusieurs clients ouvre une alerte de fraude.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
msisdnstringyes

Numéro mobile money de la RDC, avec ou sans +243.

providerstringno

Opérateur ; lu depuis le numéro si absent.

airtel · mpesa · orange · afrimoney

labelstringno

Nom du porte-monnaie ; l'opérateur par défaut.

Request example

{
  "msisdn": "+243810000000"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/saved-wallets" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "msisdn": "+243810000000"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-wallets');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "msisdn": "+243810000000"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/saved-wallets",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "msisdn": "+243810000000"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-wallets", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "msisdn": "+243810000000"
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "wallet": {
    "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "label": "texte",
    "provider": "airtel",
    "providerLabel": "texte",
    "last4": "texte",
    "maskedNumber": "texte",
    "status": "pending",
    "verified": true,
    "default": true,
    "createdAt": "2026-10-01T09:30:00Z"
  },
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
}

Answers and errors

StatusMeaning
201

Porte-monnaie enregistré.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

PATCH /v1/saved-wallets/{id}

Rename a wallet or make it the default one

The detailed descriptions of this sheet are written in French.

label : nom (1 à 40 caractères) ; default : true en fait le porte-monnaie proposé en premier (il doit être vérifié). Un champ absent est laissé tel quel.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Request body

NameTypeRequiredDescription
labelstringno
defaultbooleanno

Request example

{
  "label": "texte",
  "default": true
}

Code example

curl -X PATCH "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "label": "texte",
  "default": true
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "label": "texte",
  "default": true
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.patch(
    "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "label": "texte",
        "default": True
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "PATCH",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "label": "texte",
    "default": true
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "label": "texte",
  "provider": "airtel",
  "providerLabel": "texte",
  "last4": "texte",
  "maskedNumber": "texte",
  "status": "pending",
  "verified": true,
  "default": true,
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Porte-monnaie mis à jour.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

DELETE /v1/saved-wallets/{id}

Delete a saved wallet

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Code example

curl -X DELETE "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.delete(
    "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 204

Porte-monnaie supprimé.

Answers and errors

StatusMeaning
204

Porte-monnaie supprimé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/saved-wallets/{id}/code

Send the verification code of a wallet again

The detailed descriptions of this sheet are written in French.

Nouveau code par SMS au numéro du porte-monnaie (limité comme les autres codes ; le précédent est invalidé). saved_wallet_verified si le porte-monnaie est déjà vérifié.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/code" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/code');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/code",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/code", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
}

Answers and errors

StatusMeaning
200

Code envoyé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/saved-wallets/{id}/verify

Verify a wallet with the code received by SMS

The detailed descriptions of this sheet are written in French.

Preuve que le client détient le numéro. Après un code juste, le porte-monnaie est verified et peut financer un envoi (source.savedWalletId). Un code faux, expiré ou épuisé renvoie l'erreur OTP habituelle.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

idpathstringyes

Request body

NameTypeRequiredDescription
challengeIdstring (uuid)yes
codestringyes

Code à 6 chiffres reçu par SMS au numéro du porte-monnaie.

Request example

{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "code": "••••••"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "code": "••••••"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "code": "••••••"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
        "code": "••••••"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/saved-wallets/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/verify", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "code": "••••••"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "label": "texte",
  "provider": "airtel",
  "providerLabel": "texte",
  "last4": "texte",
  "maskedNumber": "texte",
  "status": "pending",
  "verified": true,
  "default": true,
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Porte-monnaie vérifié.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/transfers/{reference}/saved-wallet

Save the number of a completed transfer

The detailed descriptions of this sheet are written in French.

Proposé à la fin d'un envoi par mobile money dont la collecte a abouti (GET /v1/transfers/{reference} : source mobile_money, numéro pas encore enregistré, limite non atteinte). Enregistre le numéro de l'envoi comme porte-monnaie pending et envoie le code de vérification à ce numéro (consentement journalisé : after_payment). saved_wallet_not_found si l'envoi ne s'y prête pas.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/saved-wallet" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/saved-wallet');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/saved-wallet",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/transfers/LP-7K2Q4F/saved-wallet", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "wallet": {
    "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "label": "texte",
    "provider": "airtel",
    "providerLabel": "texte",
    "last4": "texte",
    "maskedNumber": "texte",
    "status": "pending",
    "verified": true,
    "default": true,
    "createdAt": "2026-10-01T09:30:00Z"
  },
  "challengeId": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f"
}

Answers and errors

StatusMeaning
201

Porte-monnaie enregistré, code envoyé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/me/dashboard

Show the dashboard

The detailed descriptions of this sheet are written in French.

Soldes, actions rapides, envois en cours, favoris, taux, carte, plafond, sécurité, statistiques et dernières opérations.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
X-App-Idheaderstringno

Application mobile appelante.

X-App-Platformheaderstringno

Plateforme de l'application mobile.

X-App-Versionheaderstringno

Version de l'application (par exemple 1.4.2). Sous la version minimale, réponse 426 app_update_required.

Code example

curl "https://sandbox.api.linc.cd/v1/me/dashboard" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/dashboard');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/me/dashboard",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/dashboard", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "mode": "wallet",
  "kycLevel": 1,
  "balances": [
    {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    }
  ],
  "reserved": [
    {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    }
  ],
  "actions": {
    "send": true,
    "pay": true,
    "topup": true,
    "withdraw": true,
    "card": true
  },
  "transfersInProgress": [
    {
      "reference": "LP-7K2Q4F",
      "status": "in_progress",
      "steps": [
        {
          "label": "texte",
          "done": true
        }
      ],
      "beneficiary": "texte",
      "destination": "texte",
      "country": "KE",
      "source": "texte",
      "sourceType": "mobile_money",
      "send": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "fee": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "vat": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "levy": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "total": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "receive": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "rate": "texte",
      "createdAt": "2026-10-01T09:30:00Z",
      "deliveredAt": "2026-10-01T09:30:00Z",
      "refundedAt": "2026-10-01T09:30:00Z"
    }
  ],
  "favourites": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "fullName": "texte",
      "country": "KE",
      "payoutMethod": "mobile_money",
      "destination": "texte"
    }
  ],
  "rates": [
    {
      "country": "KE",
      "name": "texte",
      "payoutMethod": "mobile_money",
      "send": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "fee": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "receive": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      }
    }
  ],
  "card": {
    "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    "network": "visa",
    "last4": "texte",
    "status": "active",
    "balance": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    }
  },
  "monthlyLimit": {
    "used": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "cap": {
      "amount": 10000,
      "currency": "USD",
      "display": "texte"
    },
    "percent": 0,
    "level": 1
  },
  "security": {
    "twoFactor": true,
    "totp": true,
    "sms": true,
    "trustedDevices": 0,
    "lastLogin": "2026-10-01T09:30:00Z"
  },
  "statistics": {
    "months": [
      {
        "label": "texte",
        "sent": 0,
        "received": 0,
        "paid": 0
      }
    ],
    "max": 0,
    "destinations": [
      {
        "name": "texte",
        "count": 0,
        "percent": 0
      }
    ]
  },
  "recent": [
    {
      "type": "send",
      "label": "texte",
      "date": "2026-10-01T09:30:00Z",
      "statusLabel": "texte",
      "amount": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "reference": "LP-7K2Q4F",
      "receipt": true
    }
  ]
}

Answers and errors

StatusMeaning
200

Tableau de bord du client.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/me/history

Show the history

The detailed descriptions of this sheet are written in French.

Historique paginé, filtré par type et par texte (libellé ou référence).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
pagequeryintegerno
perPagequeryintegerno
typequerystringno

Filtre. Valeur vide ou inconnue = tout.

qquerystringno

Texte recherché dans le libellé ou la référence.

Code example

curl "https://sandbox.api.linc.cd/v1/me/history" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/me/history');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/me/history",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/me/history", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "items": [
    {
      "type": "send",
      "label": "texte",
      "date": "2026-10-01T09:30:00Z",
      "statusLabel": "texte",
      "amount": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "reference": "LP-7K2Q4F",
      "receipt": true
    }
  ],
  "page": 0,
  "perPage": 0,
  "total": 0,
  "hasMore": true,
  "filters": [
    "texte"
  ]
}

Answers and errors

StatusMeaning
200

Page d'historique.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/receipts/{reference}

Download a receipt

The detailed descriptions of this sheet are written in French.

Reçu PDF d'un envoi (LP-), d'un paiement marchand (TX-), d'un rechargement (TU-) ou d'une opération crypto (CX-).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Code example

curl "https://sandbox.api.linc.cd/v1/receipts/LP-7K2Q4F" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/receipts/LP-7K2Q4F');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/receipts/LP-7K2Q4F",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/receipts/LP-7K2Q4F", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

File (PDF or image)

Answers and errors

StatusMeaning
200

Reçu PDF (pièce jointe recu-linc-{reference}.pdf).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/notifications

List my notifications

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/notifications" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/notifications');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/notifications",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/notifications", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "notifications": [
    {
      "key": "texte",
      "title": "texte",
      "text": "texte",
      "date": "2026-10-01T09:30:00Z",
      "reference": "LP-7K2Q4F",
      "read": true
    }
  ],
  "unread": 0
}

Answers and errors

StatusMeaning
200

Notifications et nombre de non lues.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/notifications/{key}/read

Mark a notification as read

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
keypathstringyes

Clé de la notification, par exemple transfer:LP-7K2Q9M:delivered.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/notifications/texte/read" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/notifications/texte/read');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/notifications/texte/read",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/notifications/texte/read", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 204

Notification lue.

Answers and errors

StatusMeaning
204

Notification lue.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/notifications/read-all

Mark everything as read

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/notifications/read-all" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/notifications/read-all');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/notifications/read-all",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/notifications/read-all", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "marked": 0
}

Answers and errors

StatusMeaning
200

Nombre de notifications marquées.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/wallet/top-ups

List my top-ups

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/wallet/top-ups" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/wallet/top-ups');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/wallet/top-ups",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/wallet/top-ups", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "topUps": [
    {
      "reference": "LP-7K2Q4F",
      "status": "pending",
      "provider": "airtel",
      "amount": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "failureReason": "texte",
      "createdAt": "2026-10-01T09:30:00Z",
      "completedAt": "2026-10-01T09:30:00Z"
    }
  ]
}

Answers and errors

StatusMeaning
200

Rechargements du client.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/wallet/top-ups

Top up the balance

The detailed descriptions of this sheet are written in French.

Collecte USSD / STK push sur le mobile money. Le résultat est asynchrone (suivez le statut).

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

Request body

NameTypeRequiredDescription
providerstringno

airtel · mpesa · orange · afrimoney

msisdnstringno

Numéro à débiter. Vide = numéro du compte.

amountstringyes
currencystringno

Request example

{
  "amount": "texte"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/wallet/top-ups" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": "texte"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/wallet/top-ups');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "amount": "texte"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/wallet/top-ups",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "amount": "texte"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/wallet/top-ups", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "amount": "texte"
  }),
});
console.log(answer.status, await answer.text());

Answer example 202

{
  "reference": "LP-7K2Q4F",
  "status": "pending",
  "provider": "airtel",
  "amount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "failureReason": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "completedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
202

Rechargement lancé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/wallet/top-ups/{reference}

Track a top-up

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Code example

curl "https://sandbox.api.linc.cd/v1/wallet/top-ups/LP-7K2Q4F" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/wallet/top-ups/LP-7K2Q4F');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/wallet/top-ups/LP-7K2Q4F",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/wallet/top-ups/LP-7K2Q4F", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "status": "pending",
  "provider": "airtel",
  "amount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "failureReason": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "completedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Rechargement.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/merchant-payments/resolve

Read a merchant QR code or payment link

The detailed descriptions of this sheet are written in French.

Ce que demande un QR scanné (EMVCo) ou un lien INV-… ouvert, avant de payer.

Authentication: Customer token: Authorization: Bearer <access token>

Request body

NameTypeRequiredDescription
payloadstringyes

Contenu du QR EMVCo, lien https://app.linc.cd/pay/INV-… ou référence INV-….

Request example

{
  "payload": "texte"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/merchant-payments/resolve" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "payload": "texte"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/merchant-payments/resolve');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "payload": "texte"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/merchant-payments/resolve",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "payload": "texte"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/merchant-payments/resolve", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "payload": "texte"
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "type": "link",
  "reference": "LP-7K2Q4F",
  "merchant": {
    "code": "••••••",
    "name": "texte",
    "country": "KE"
  },
  "label": "texte",
  "amount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "status": "open",
  "payable": true,
  "expiresAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Marchand, montant et état du paiement demandé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/merchant-payments

List my merchant payments

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/merchant-payments" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/merchant-payments');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/merchant-payments",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/merchant-payments", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "payments": [
    {
      "reference": "LP-7K2Q4F",
      "status": "pending",
      "statusLabel": "texte",
      "merchant": {
        "code": "••••••",
        "name": "texte",
        "country": "KE"
      },
      "label": "texte",
      "channel": "link",
      "source": "mobile_money",
      "amount": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "createdAt": "2026-10-01T09:30:00Z",
      "paidAt": "2026-10-01T09:30:00Z",
      "refundedAt": "2026-10-01T09:30:00Z"
    }
  ]
}

Answers and errors

StatusMeaning
200

Paiements du client.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/merchant-payments

Pay a merchant

The detailed descriptions of this sheet are written in French.

Paie un lien (INV-…) ou un QR de caisse (QR-…, montant obligatoire). Second facteur requis, sauf par carte bancaire : la réponse donne alors la page carte (cardCheckout) où la carte est saisie et confirmée par sa banque (3-D Secure). La collecte est asynchrone. Opération sensible : assertion X-Linc-Attestation exigée des applications attestées.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
referencestringyes
amountstringno

Obligatoire pour un QR de caisse (USD).

sourceobjectno
source.typestringno

mobile_money · wallet · card

source.providerstringno

airtel · mpesa · orange · afrimoney

source.msisdnstringno
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "reference": "INV-7K2Q4F",
  "source": {
    "type": "mobile_money",
    "provider": "airtel",
    "msisdn": "+243970000000"
  },
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/merchant-payments" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "reference": "INV-7K2Q4F",
  "source": {
    "type": "mobile_money",
    "provider": "airtel",
    "msisdn": "+243970000000"
  },
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/merchant-payments');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "reference": "INV-7K2Q4F",
  "source": {
    "type": "mobile_money",
    "provider": "airtel",
    "msisdn": "+243970000000"
  },
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/merchant-payments",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "reference": "INV-7K2Q4F",
        "source": {
            "type": "mobile_money",
            "provider": "airtel",
            "msisdn": "+243970000000"
        },
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/merchant-payments", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "reference": "INV-7K2Q4F",
    "source": {
      "type": "mobile_money",
      "provider": "airtel",
      "msisdn": "+243970000000"
    },
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 202

{
  "reference": "LP-7K2Q4F",
  "status": "pending",
  "statusLabel": "texte",
  "merchant": {
    "code": "••••••",
    "name": "texte",
    "country": "KE"
  },
  "label": "texte",
  "channel": "link",
  "source": "mobile_money",
  "amount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "createdAt": "2026-10-01T09:30:00Z",
  "paidAt": "2026-10-01T09:30:00Z",
  "refundedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
202

Paiement accepté, en cours.

422

Refus métier (Problem.code), dont journey_limit_exceeded : le montant dépasse un plafond du parcours de paiement (par envoi, par jour ou par mois, en USD quelle que soit la devise envoyée, docs/adr/0083). detail donne le plafond atteint (« 30.00 USD »). Un parcours fermé répond operation_unavailable (403), sans motif.

Error as application/problem+json: see “Errors”.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/merchant-payments/{reference}

Show a merchant payment

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence du paiement marchand.

Code example

curl "https://sandbox.api.linc.cd/v1/merchant-payments/LP-7K2Q4F" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/merchant-payments/LP-7K2Q4F');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/merchant-payments/LP-7K2Q4F",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/merchant-payments/LP-7K2Q4F", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "status": "pending",
  "statusLabel": "texte",
  "merchant": {
    "code": "••••••",
    "name": "texte",
    "country": "KE"
  },
  "label": "texte",
  "channel": "link",
  "source": "mobile_money",
  "amount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "createdAt": "2026-10-01T09:30:00Z",
  "paidAt": "2026-10-01T09:30:00Z",
  "refundedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Paiement marchand.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/withdrawal-codes

List my withdrawal codes

The detailed descriptions of this sheet are written in French.

Le code complet n'est jamais renvoyé (code = null).

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/withdrawal-codes" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/withdrawal-codes');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/withdrawal-codes",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/withdrawal-codes", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "codes": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "status": "active",
      "statusLabel": "texte",
      "code": "••••••",
      "last4": "texte",
      "amount": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "createdAt": "2026-10-01T09:30:00Z",
      "expiresAt": "2026-10-01T09:30:00Z",
      "closedAt": "2026-10-01T09:30:00Z"
    }
  ]
}

Answers and errors

StatusMeaning
200

Codes de retrait.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/withdrawal-codes

Create a withdrawal code

The detailed descriptions of this sheet are written in French.

Code à 8 chiffres, affiché une seule fois, à donner à l'agent avec une pièce d'identité. Le montant est réservé. Second facteur requis. Opération sensible (X-Linc-Attestation).

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
amountstringyes
currencystringno
twoFactorobjectyes

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringyes

totp · sms · backup_code

twoFactor.codestringyes
twoFactor.challengeIdstring (uuid)no

Request example

{
  "amount": "texte",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/withdrawal-codes" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": "texte",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/withdrawal-codes');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "amount": "texte",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/withdrawal-codes",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "amount": "texte",
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/withdrawal-codes", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "amount": "texte",
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "status": "active",
  "statusLabel": "texte",
  "code": "••••••",
  "last4": "texte",
  "amount": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "createdAt": "2026-10-01T09:30:00Z",
  "expiresAt": "2026-10-01T09:30:00Z",
  "closedAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
201

Code créé (champ code présent une seule fois).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/withdrawal-codes/{id}/cancel

Cancel a withdrawal code

The detailed descriptions of this sheet are written in French.

Libère le montant réservé.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/withdrawal-codes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/cancel" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/withdrawal-codes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/cancel');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/withdrawal-codes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/cancel",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/withdrawal-codes/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/cancel", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 204

Code annulé.

Answers and errors

StatusMeaning
204

Code annulé.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/cards

List my virtual cards

The detailed descriptions of this sheet are written in French.

Cartes du client et programmes ouverts à la création.

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/cards" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/cards",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "cards": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "last4": "texte",
      "network": "visa",
      "currency": "USD",
      "embossedName": "texte",
      "status": "active",
      "frozenByCompliance": true,
      "model": "companion",
      "balance": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      },
      "limits": {
        "perTransaction": 0,
        "daily": 0,
        "monthly": 0,
        "ecommerce": true
      },
      "closeReason": "texte",
      "replacedBy": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "programmes": [
    {
      "network": "visa",
      "currency": "USD"
    }
  ]
}

Answers and errors

StatusMeaning
200

Cartes et programmes ouverts.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/cards

Create a virtual card

The detailed descriptions of this sheet are written in French.

Mode wallet et KYC niveau 2 requis. Second facteur requis.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
networkstringno

visa · mastercard

embossedNamestringno
twoFactorobjectyes

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringyes

totp · sms · backup_code

twoFactor.codestringyes
twoFactor.challengeIdstring (uuid)no

Request example

{
  "network": "visa",
  "embossedName": "AMANI K",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/cards" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "network": "visa",
  "embossedName": "AMANI K",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "network": "visa",
  "embossedName": "AMANI K",
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/cards",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "network": "visa",
        "embossedName": "AMANI K",
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "network": "visa",
    "embossedName": "AMANI K",
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "id": "0192a7c4-7a13-7d0b-b8c4-1e5f6a2b3c44",
  "last4": "4821",
  "network": "visa",
  "currency": "USD",
  "embossedName": "AMANI K",
  "status": "active",
  "frozenByCompliance": false,
  "model": "companion",
  "balance": {
    "amount": 0,
    "currency": "USD",
    "display": "0,00 $"
  },
  "limits": {
    "perTransaction": 100000,
    "daily": 200000,
    "monthly": 500000,
    "ecommerce": true
  },
  "closeReason": null,
  "replacedBy": null,
  "createdAt": "2026-09-29T14:02:00+00:00"
}

Answers and errors

StatusMeaning
201

Carte créée.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/cards/{id}

Show a card

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

Code example

curl "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "last4": "texte",
  "network": "visa",
  "currency": "USD",
  "embossedName": "texte",
  "status": "active",
  "frozenByCompliance": true,
  "model": "companion",
  "balance": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "limits": {
    "perTransaction": 0,
    "daily": 0,
    "monthly": 0,
    "ecommerce": true
  },
  "closeReason": "texte",
  "replacedBy": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Carte.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/cards/{id}/transactions

List the operations of a card

The detailed descriptions of this sheet are written in French.

Paiements, refus et chargements, du plus récent au plus ancien (100 au plus).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

Code example

curl "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/transactions" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/transactions');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/transactions",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/transactions", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "transactions": [
    {
      "kind": "payment",
      "label": "texte",
      "date": "2026-10-01T09:30:00Z",
      "status": "texte",
      "detail": "texte",
      "amount": {
        "amount": 10000,
        "currency": "USD",
        "display": "texte"
      }
    }
  ]
}

Answers and errors

StatusMeaning
200

Opérations de la carte.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/cards/{id}/freeze

Freeze a card

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/freeze" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/freeze');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/freeze",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/freeze", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "last4": "texte",
  "network": "visa",
  "currency": "USD",
  "embossedName": "texte",
  "status": "active",
  "frozenByCompliance": true,
  "model": "companion",
  "balance": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "limits": {
    "perTransaction": 0,
    "daily": 0,
    "monthly": 0,
    "ecommerce": true
  },
  "closeReason": "texte",
  "replacedBy": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Carte.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/cards/{id}/unfreeze

Unfreeze a card

The detailed descriptions of this sheet are written in French.

Impossible si la conformité a gelé la carte.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/unfreeze" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/unfreeze');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/unfreeze",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/unfreeze", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "last4": "texte",
  "network": "visa",
  "currency": "USD",
  "embossedName": "texte",
  "status": "active",
  "frozenByCompliance": true,
  "model": "companion",
  "balance": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "limits": {
    "perTransaction": 0,
    "daily": 0,
    "monthly": 0,
    "ecommerce": true
  },
  "closeReason": "texte",
  "replacedBy": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Carte.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/cards/{id}/reveal

Show the card details

The detailed descriptions of this sheet are written in French.

Retourne une session d'affichage (60 s) pour le SDK de l'émetteur, après un second facteur. Aucune donnée de carte ne transite par Linc.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/reveal" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/reveal');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/reveal",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/reveal", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "issuer": "texte",
  "cardReference": "LP-7K2Q4F",
  "last4": "texte",
  "sdkUrl": "https://example.com",
  "expiresAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Session d'affichage.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/cards/{id}/replace

Replace a card

The detailed descriptions of this sheet are written in French.

Ferme la carte (perdue ou compromise) et en crée une nouvelle. Second facteur requis.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
reasonstringno

lost · compromised

twoFactorobjectyes

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringyes

totp · sms · backup_code

twoFactor.codestringyes
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/replace" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/replace');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/replace",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/replace", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "last4": "texte",
  "network": "visa",
  "currency": "USD",
  "embossedName": "texte",
  "status": "active",
  "frozenByCompliance": true,
  "model": "companion",
  "balance": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "limits": {
    "perTransaction": 0,
    "daily": 0,
    "monthly": 0,
    "ecommerce": true
  },
  "closeReason": "texte",
  "replacedBy": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
201

Nouvelle carte.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/cards/{id}/terminate

Close a card

The detailed descriptions of this sheet are written in French.

Fermeture définitive. Second facteur requis.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/terminate" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/terminate');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/terminate",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/terminate", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "last4": "texte",
  "network": "visa",
  "currency": "USD",
  "embossedName": "texte",
  "status": "active",
  "frozenByCompliance": true,
  "model": "companion",
  "balance": {
    "amount": 10000,
    "currency": "USD",
    "display": "texte"
  },
  "limits": {
    "perTransaction": 0,
    "daily": 0,
    "monthly": 0,
    "ecommerce": true
  },
  "closeReason": "texte",
  "replacedBy": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
  "createdAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
200

Carte fermée.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/cards/{id}/credential-show-session

Open a card display session (mobile SDK)

The detailed descriptions of this sheet are written in French.

Même contrôle que reveal (second facteur, audit) pour le SDK Credential Show de l'émetteur sur Android et iOS. L'application passe cardReference au SDK, qui affiche les détails lui-même. Opération sensible (X-Linc-Attestation).

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
idpathstringyes

Identifiant de la carte.

X-App-Platformheaderstringno

Plateforme de l'application mobile.

X-Linc-Attestationheaderstringno

Assertion de l'installation attestée, pour une opération sensible. Hachage de la requête : base64url(SHA-256(METHOD "\n" PATH "\n" Idempotency-Key "\n" hex(SHA-256(corps)))). Android : jeton Play Integrity (requête standard) avec ce requestHash. iOS : assertion App Attest (CBOR en base64) sur le SHA-256 de ce hachage. Absente ou invalide quand la politique l'exige : 403 attestation_required.

Request body

NameTypeRequiredDescription
twoFactorobjectno

Preuve de second facteur. Pour sms, joignez le challengeId du code reçu. Certaines opérations demandent un code saisi à l'instant, jamais un code de secours : le code de l'application d'authentification quand elle est activée depuis un certain temps, sinon un code SMS envoyé au téléphone vérifié (à demander avec POST /v1/me/security/otp, même si la double authentification par SMS n'est pas activée). Un autre moyen répond two_factor_method_unavailable (422), avec le moyen attendu dans le message. Quand aucun moyen ne convient, l'opération répond operation_unavailable (403) ou est mise en attente.

twoFactor.methodstringno

totp · sms · backup_code

twoFactor.codestringno
twoFactor.challengeIdstring (uuid)no

Request example

{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/credential-show-session" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/credential-show-session');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "twoFactor": {
    "method": "totp",
    "code": "••••••"
  }
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/credential-show-session",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "twoFactor": {
            "method": "totp",
            "code": "••••••"
        }
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/cards/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f/credential-show-session", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "twoFactor": {
      "method": "totp",
      "code": "••••••"
    }
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "issuer": "texte",
  "cardReference": "LP-7K2Q4F",
  "last4": "texte",
  "platform": "android",
  "expiresAt": "2026-10-01T09:30:00Z"
}

Answers and errors

StatusMeaning
201

Session pour le SDK Credential Show de l'émetteur.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/tickets/options

List the request types and categories

The detailed descriptions of this sheet are written in French.

Types (réclamation, demande d'information), catégories et contraintes des pièces jointes.

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/tickets/options" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets/options');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/tickets/options",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets/options", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "types": [
    {
      "code": "complaint",
      "label": "texte"
    }
  ],
  "categories": [
    {
      "code": "transfer",
      "label": "texte"
    }
  ],
  "attachments": {
    "types": [
      "texte"
    ],
    "maxBytes": 0
  }
}

Answers and errors

StatusMeaning
200

Options du formulaire de demande.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/tickets

List my requests

Authentication: Customer token: Authorization: Bearer <access token>

Code example

curl "https://sandbox.api.linc.cd/v1/tickets" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/tickets",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "items": [
    {
      "reference": "LP-7K2Q4F",
      "type": "complaint",
      "category": "transfer",
      "categoryLabel": "texte",
      "subject": "texte",
      "linkedReference": "LP-7K2Q4F",
      "status": "received",
      "statusLabel": "texte",
      "createdAt": "2026-10-01T09:30:00Z",
      "updatedAt": "2026-10-01T09:30:00Z"
    }
  ]
}

Answers and errors

StatusMeaning
200

Demandes du client, de la plus récente à la plus ancienne.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/tickets

Open a request

The detailed descriptions of this sheet are written in French.

Ouvre une réclamation ou une demande d'information (référence TK-XXXXXX). Erreur 422 validation_failed ou ticket_invalid si le formulaire est incomplet.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

Request body

NameTypeRequiredDescription
typestringyes

complaint : réclamation ; information : demande d'information.

complaint · information

categorystringyes

transfer · merchant_payment · top_up · withdrawal_agent · card · kyc · account_security · fraud · technical · other

subjectstringyes
descriptionstringyes
linkedReferencestringno

LP-…, INV-…, TX-…, TU-…, AG-…, QR-…, CL-…, RG-… ou CARD-1234 (4 derniers chiffres).

Request example

{
  "type": "complaint",
  "category": "transfer",
  "subject": "texte",
  "description": "texte"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/tickets" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "type": "complaint",
  "category": "transfer",
  "subject": "texte",
  "description": "texte"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "type": "complaint",
  "category": "transfer",
  "subject": "texte",
  "description": "texte"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/tickets",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "type": "complaint",
        "category": "transfer",
        "subject": "texte",
        "description": "texte"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "type": "complaint",
    "category": "transfer",
    "subject": "texte",
    "description": "texte"
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "reference": "LP-7K2Q4F",
  "type": "complaint",
  "category": "transfer",
  "categoryLabel": "texte",
  "subject": "texte",
  "linkedReference": "LP-7K2Q4F",
  "status": "received",
  "statusLabel": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "updatedAt": "2026-10-01T09:30:00Z",
  "messages": [
    {
      "author": "texte",
      "mine": true,
      "body": "texte",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "attachments": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "filename": "texte",
      "mimeType": "application/pdf",
      "size": 0,
      "mine": true,
      "scan": "pending",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "canReply": true,
  "canReopen": true,
  "reopenUntil": "2026-10-01T09:30:00Z",
  "canRate": true,
  "satisfaction": 0,
  "suggestedActions": [
    "freeze_card"
  ]
}

Answers and errors

StatusMeaning
201

Demande ouverte.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/tickets/{reference}

Show a request

The detailed descriptions of this sheet are written in French.

Fil des échanges, pièces jointes et actions possibles. Erreur 404 ticket_not_found.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de la demande.

Code example

curl "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "type": "complaint",
  "category": "transfer",
  "categoryLabel": "texte",
  "subject": "texte",
  "linkedReference": "LP-7K2Q4F",
  "status": "received",
  "statusLabel": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "updatedAt": "2026-10-01T09:30:00Z",
  "messages": [
    {
      "author": "texte",
      "mine": true,
      "body": "texte",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "attachments": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "filename": "texte",
      "mimeType": "application/pdf",
      "size": 0,
      "mine": true,
      "scan": "pending",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "canReply": true,
  "canReopen": true,
  "reopenUntil": "2026-10-01T09:30:00Z",
  "canRate": true,
  "satisfaction": 0,
  "suggestedActions": [
    "freeze_card"
  ]
}

Answers and errors

StatusMeaning
200

Demande.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/tickets/{reference}/messages

Reply to a request

The detailed descriptions of this sheet are written in French.

Ajoute un message au fil. Erreur 404 ticket_not_found, 409 ticket_closed si la demande est clôturée.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de la demande.

Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

Request body

NameTypeRequiredDescription
bodystringyes

Request example

{
  "body": "texte"
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/messages" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "texte"
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/messages');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16)), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "body": "texte"
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/messages",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    json={
        "body": "texte"
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/messages", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json" },
  body: JSON.stringify({
    "body": "texte"
  }),
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "reference": "LP-7K2Q4F",
  "type": "complaint",
  "category": "transfer",
  "categoryLabel": "texte",
  "subject": "texte",
  "linkedReference": "LP-7K2Q4F",
  "status": "received",
  "statusLabel": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "updatedAt": "2026-10-01T09:30:00Z",
  "messages": [
    {
      "author": "texte",
      "mine": true,
      "body": "texte",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "attachments": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "filename": "texte",
      "mimeType": "application/pdf",
      "size": 0,
      "mine": true,
      "scan": "pending",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "canReply": true,
  "canReopen": true,
  "reopenUntil": "2026-10-01T09:30:00Z",
  "canRate": true,
  "satisfaction": 0,
  "suggestedActions": [
    "freeze_card"
  ]
}

Answers and errors

StatusMeaning
201

Demande mise à jour.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/tickets/{reference}/attachments

Attach a file to a request

The detailed descriptions of this sheet are written in French.

Envoie un fichier dans le champ multipart file (PDF, JPEG ou PNG, 10 Mo maximum), analysé par l'antivirus avant de pouvoir être lu. Erreurs 422 attachment_type_refused ou attachment_too_large, 409 attachment_limit_reached.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de la demande.

Request body

File sent as multipart/form-data.

NameTypeRequiredDescription
filestringyes

Fichier (PDF, JPEG ou PNG, 10 Mo maximum).

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -F "file=@document.jpg"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_POSTFIELDS => ['file' => new CURLFile('document.jpg')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    files={"file": open("document.jpg", "rb")},
    timeout=30,
)
print(answer.status_code, answer.text)
import { openAsBlob } from "node:fs";

const form = new FormData();
form.append("file", await openAsBlob("document.jpg"), "document.jpg");

const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
  body: form,
});
console.log(answer.status, await answer.text());

Answer example 201

{
  "reference": "LP-7K2Q4F",
  "type": "complaint",
  "category": "transfer",
  "categoryLabel": "texte",
  "subject": "texte",
  "linkedReference": "LP-7K2Q4F",
  "status": "received",
  "statusLabel": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "updatedAt": "2026-10-01T09:30:00Z",
  "messages": [
    {
      "author": "texte",
      "mine": true,
      "body": "texte",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "attachments": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "filename": "texte",
      "mimeType": "application/pdf",
      "size": 0,
      "mine": true,
      "scan": "pending",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "canReply": true,
  "canReopen": true,
  "reopenUntil": "2026-10-01T09:30:00Z",
  "canRate": true,
  "satisfaction": 0,
  "suggestedActions": [
    "freeze_card"
  ]
}

Answers and errors

StatusMeaning
201

Demande mise à jour.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

GET /v1/tickets/{reference}/attachments/{id}

Download an attachment

The detailed descriptions of this sheet are written in French.

Adresse renvoyée par …/attachments/{id}/link, valable 5 minutes et liée à l'utilisateur qui l'a demandée ; le jeton d'accès reste exigé. Erreurs 403 attachment_link_invalid (lien expiré, altéré ou d'un autre utilisateur), 409 attachment_unavailable.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de la demande.

idpathstringyes

Identifiant de la pièce jointe.

viewerquerystringyes

Utilisateur auquel le lien est lié (fourni par le lien signé).

_expiresquerystringyes

Expiration du lien (fournie par le lien signé).

_signaturequerystringyes

Signature du lien.

Code example

curl "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f?viewer=texte&_expires=texte&_signature=texte" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f?viewer=texte&_expires=texte&_signature=texte');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN')],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.get(
    "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f?viewer=texte&_expires=texte&_signature=texte",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/attachments/0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f?viewer=texte&_expires=texte&_signature=texte", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}` },
});
console.log(answer.status, await answer.text());

Answer example 200

File (PDF or image)

Answers and errors

StatusMeaning
200

Contenu de la pièce jointe (téléchargement, jamais mis en cache).

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/tickets/{reference}/reopen

Reopen a request

The detailed descriptions of this sheet are written in French.

Possible pendant un délai après la résolution (reopenUntil). Erreur 409 ticket_not_reopenable.

Authentication: Customer token: Authorization: Bearer <access token>

Financial operation: send a unique Idempotency-Key per operation (replayed for 24 h).

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de la demande.

Idempotency-Keyheaderstringyes

Identifiant unique de l'opération (par exemple un UUID), conservé 24 h. Une même clé avec le même corps rejoue la réponse d'origine. Avec un autre corps : 422 idempotency_key_reused. Pendant le traitement : 409 idempotency_in_progress.

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/reopen" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/reopen');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Idempotency-Key: ' . bin2hex(random_bytes(16))],
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os
import uuid

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/reopen",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/reopen", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Idempotency-Key": crypto.randomUUID() },
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "type": "complaint",
  "category": "transfer",
  "categoryLabel": "texte",
  "subject": "texte",
  "linkedReference": "LP-7K2Q4F",
  "status": "received",
  "statusLabel": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "updatedAt": "2026-10-01T09:30:00Z",
  "messages": [
    {
      "author": "texte",
      "mine": true,
      "body": "texte",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "attachments": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "filename": "texte",
      "mimeType": "application/pdf",
      "size": 0,
      "mine": true,
      "scan": "pending",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "canReply": true,
  "canReopen": true,
  "reopenUntil": "2026-10-01T09:30:00Z",
  "canRate": true,
  "satisfaction": 0,
  "suggestedActions": [
    "freeze_card"
  ]
}

Answers and errors

StatusMeaning
200

Demande.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.

POST /v1/tickets/{reference}/satisfaction

Rate the handling of a request

The detailed descriptions of this sheet are written in French.

Une seule note par demande résolue ou clôturée. Erreurs 409 ticket_already_rated, 422 validation_failed.

Authentication: Customer token: Authorization: Bearer <access token>

Parameters

NameInTypeRequiredDescription
referencepathstringyes

Référence publique de la demande.

Request body

NameTypeRequiredDescription
scoreintegeryes
commentstringno

Request example

{
  "score": 0
}

Code example

curl -X POST "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/satisfaction" \
  -H "Authorization: Bearer $LINC_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "score": 0
}'
<?php
$ch = curl_init('https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/satisfaction');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('LINC_ACCESS_TOKEN'), 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "score": 0
}
JSON,
    CURLOPT_RETURNTRANSFER => true,
]);
$answer = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;
print_r($answer);
import os

import requests

answer = requests.post(
    "https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/satisfaction",
    headers={"Authorization": f"Bearer {os.environ['LINC_ACCESS_TOKEN']}"},
    json={
        "score": 0
    },
    timeout=30,
)
print(answer.status_code, answer.text)
const answer = await fetch("https://sandbox.api.linc.cd/v1/tickets/LP-7K2Q4F/satisfaction", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.LINC_ACCESS_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "score": 0
  }),
});
console.log(answer.status, await answer.text());

Answer example 200

{
  "reference": "LP-7K2Q4F",
  "type": "complaint",
  "category": "transfer",
  "categoryLabel": "texte",
  "subject": "texte",
  "linkedReference": "LP-7K2Q4F",
  "status": "received",
  "statusLabel": "texte",
  "createdAt": "2026-10-01T09:30:00Z",
  "updatedAt": "2026-10-01T09:30:00Z",
  "messages": [
    {
      "author": "texte",
      "mine": true,
      "body": "texte",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "attachments": [
    {
      "id": "0190f1b4-7c3a-7d2e-9a51-3f2b8c1d4e5f",
      "filename": "texte",
      "mimeType": "application/pdf",
      "size": 0,
      "mine": true,
      "scan": "pending",
      "createdAt": "2026-10-01T09:30:00Z"
    }
  ],
  "canReply": true,
  "canReopen": true,
  "reopenUntil": "2026-10-01T09:30:00Z",
  "canRate": true,
  "satisfaction": 0,
  "suggestedActions": [
    "freeze_card"
  ]
}

Answers and errors

StatusMeaning
200

Demande.

Any other error

Erreur (RFC 9457).

Error as application/problem+json: see “Errors”.