Outbound transfers
Initiate real-time payments using our outbound Transfers API
To start creating payouts using Fintoc's Transfers API, you just need to create an account on our Dashboard and follow these six steps:
- Get your test API Keys
- Configure JWS Signing Keys
- Generate JWS Signature
- Add funds to the account indicated by Fintoc.
- From your backend, create a
Transfer
using your Secret Key and a JWS Signature - Monitor transfer status
The following diagram shows how Fintoc will interact with you and the counterparty receiving the payout.
Step 1: Get your test Secret API Key
Every interaction with the Fintoc API must be authenticated with the API Keys of your Fintoc account. If an interaction does not include your API Key or includes an incorrect API Key, Fintoc will return an error.
Every Fintoc account has two key pairs: one corresponds to the test mode and the other to the live API environment. Every resource is stored either in test mode or in live mode, and resources from one environment cannot be manipulated by resources from the other environment.
Your API Keys will be available in the Dashboard. First you need to create an account on the Fintoc Dashboard. Once your Fintoc account has been created, you will be able to get your API Keys. In this case, you must use the Secret Key from test mode. We added the prefix sk_test_to quickly identify it.
Keep your keys safe
Anyone can use your live mode secret API Key to make transfers on behalf of your account.
Step 2: Configure JWS Signing Keys
To make requests to our Transfers endpoints, a JSON Web Signature (JWS) is required. JWS is a standard mechanism used to digitally sign a piece of data to ensure its integrity and authenticity.
To sign an API call, you'll need to follow these steps:
Generate a pair of Public and Private JWS Keys
Execute this command in your terminal:
openssl genrsa -out private_key.pem 2048
openssl rsa -in private_key.pem -outform PEM -pubout -out public_key.pem.pub
This generates two files:
private_key.pem
containing your private keypublic_key.pem
containing your public key
Each file should look similar to this example:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoPPSwkMAHrLy6ZY+cOIP
jl6PxkrKJBicwMBMgFPf0Vtqe6QWepeOWXQuLgW+cSDI0KBjk8eZQEVB7GY3OwOl
DcknxUkaVueEvsDiY74xeC1iN2Gfb6HXd2JqgDWdWy/HNv2eUe9kmsSPSSgruA8Y
DvR6lpjPvAEJHP4Sg/B+9c0gBTDmqadL8UD291D7JbHmG4lIBT5NbhpOVnSBN0aC
R6ioxWz+VJoz68qsxHQ69TYhl8/jG79ocvZsZEWCWc/Kv7SP6/cPJHu0oGWVZwa4
5BtPLeMQ9ZleHdV6RCUbxFXKzbZF5fKQ+z5NWk+hMz5TCs4jwmg1nodWyW+bL7K9
YQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDEbZHV0ODosbFn
BqcUYiRhlQWEJ9V9s5WfuFMv0n9hNWNFSBYiup+yuCNVW11vPQ7h6VUAWP8LFgmc
jsyjATlIsJDFDXXOQMyxAS2is2vZpot5QblcJMUxxMmAkUCJtpo7QSLKEPk2gRu4
tsQpzqnxCYDCnJOAHcClNrMIVJuczn/GMCm68IcAeNP8HQy9D20ER+w1tONoIzJ3
bQF0WkbtgJMYoQAq6UL3q0ws7ODvXo/ZcrFrY7q4skJopI+pz3qsGeSJX0PWjH4a
o+C9n5uYRXBxtH3nhnkSQdRZCk9fzId9+ObKrMKYuDxBeFqFIjZEh4pZ9lCPaHGK
qHwv3nLFAgMBAAECggEAHJnRpr7ryKX67UPoNw0VPAotS/Fa4hsweZmmrytotbhG
1JMq+fKPhz/NkUOk5qoOzTEi2dKbjDswuhWG0WM/uohPBAoyMY5433sK8IpMdVwN
KeI6gaKu/dCoAGrl6UdnzKHu1VpEVz3UUgB2rpmzX+/gyjVvOrPaVZQR3HApWlrr
qa/hmsiisCD1Bj7RreVAC6XfZCr8iyomNmX/Hz7Vx6s3HlBHzvQtxkwjjAPYu4SW
VsDAZESJNcOrZ8xNervaR3X+lLaF1DS/ntawPz6alAb46IyVgFU0K+rJn47MOTsi
gNSZqHV1TtTu7+jPkbF+LHHBYpYb4CSqyU41LKhDXwKBgQDk9smFRPjuSUiMGfI2
FCqwUmiYlAaEOHFLhvCapq2GfPjj1rIJMtqwox9fqKvHmTdiLjQ9+esyAbEG3CIW
njgsUsZspQOmCOqjuk0GsF9nsl/blzZrsytyN54xoRSECuecId6m31pQyJxoG1Y4
wqqAVObnepWb311xLIx/RI7NowKBgQDbn0WAuOv7JsXn/0CcZfzsbGRIMEkDLYe4
KiVOWALd6MijqtgyzRRwz2Qu7+AEfs0i4A0ZIOInZ2y5qkTeqpMNtqM9A4q5YClB
XTt/vUFxCLekL0s+zqXH9D87sTqEtTVNHpyJem3velXPDlSwR6MNyK0TRR7izBAg
mfYYSWV0dwKBgH6RfazSB9mRYS0xWpdSZpa5t2BA06lbmiVqHq8e3GWvx9YK5Lf5
CLMEOV+j2fGoXNlFOVPZR46JKNbl8WIXbG30BAQi4/VwkGSZo+LCtLqZ/CtjV44J
qUamQCinJrQnYwkIIBCW/1IQ04UpN2yBD8eJJ2tmdDWKMBlTywa/W0GJAoGBAJ12
WFKuQyNS7Vok/KIlzW2FWXEYjYClyEUWkqDVIVkRaalO+KuTtjAbweyVN7yBXXq/
wSRfG0a9NIr5tV8gVUbjx64bN/8pHusqeVpgyubMJT6mWgCyENKIID4gF6DGe2zL
odg/20p0H8nQsI+jDRj45H6IdFiPjpCRUoyfMwqJAoGBAJawh68qY9eQYWPwSq4g
S1RnrSmiamTm3zPqzeEZKcZOfrQz+W8q3Woq90HkupglXspL6bar6rZnuhcqY1xU
5m7IDq3fFRjfvsNDft5YJrtLFsJ/Uu6UHVnOa9K53aUJczMZ3CetqhJZmYvR9BPV
Yfo0J11kYXclnb1wH0svjZEA
-----END PRIVATE KEY-----
Never share your JWS Private Key
Your JWS Private Key is highly sensitive and must remain confidential at all times. Fintoc will never ask for this key. If someone gains access to your private key, they could maliciously sign transfer requests on your behalf.
Upload your Public Key to the Dashboard
- Go to dashboard.fintoc.com
- Go to the API Keys tab on the side bar
- If products that require JWS are active for your organization, you'll see a JWS Public Keys section. Click the "Add JWS Key" button and upload your JWS Public Key.
Step 3: Generate JWS Signature
Now that you loaded your Public Key to your Fintoc Dashboard, you can generate a signature based on the Private Key. This is necessary to ensure integrity and authenticity for each Transfer API call.
Step by step example
Prepare the payload
For JWS signature generation, we need to work with the exact JSON string that will be sent in the HTTP request. This is typically created by converting your Outbound Transfer request body object into a JSON string using your language's JSON serializer.
body = { ... } # your request body
raw_body = json.dumps(body)
const body = { ... } // your request body
const rawBody = JSON.stringify(body)
body = { ... } # your request body
raw_body = body.to_json
JSON string must be consistent
When serializing your request body to JSON, you must use the exact same string for two purposes:
- Creating the JWS signature
- Sending as the payload in your HTTP request
Any slight difference between the JSON used to create the JWS signature and the payload in your HTTP request may invalidate the signature.
Load Private Key and Configure Headers
Load your private key from the PEM file and set up the JWS headers. Headers include the signing algorithm (RS256), a unique nonce to prevent duplicated signatures, current timestamp, and critical fields specification.
# load the private key
with open('./private_key.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(
f.read(),
password=None
)
# define jws headers
headers = {
"alg": "RS256", # signing algorithm. must be "RS256"
"nonce": secrets.token_hex(16), # unique string for each request
"ts": int(time.time()), # timestamp of the request
"crit": ["ts", "nonce"] # critical headers
}
// load the private key
const privateKey = readFileSync('./private_key.pem', 'utf8');
// define jws headers
const headers = {
alg: 'RS256', // signing algorithm. must be "RS256"
nonce: crypto.randomBytes(16).toString('hex'), // unique string for each request
iat: Math.floor(Date.now() / 1000), // timestamp of the request
crit: ['iat', 'nonce'] // critical headers
};
# load the private key
private_key = OpenSSL::PKey::RSA.new(File.read('./private_key.pem'))
# define jws headers
headers = {
'alg' => 'RS256', # signing algorithm. must be "RS256"
'nonce' => SecureRandom.hex(16), # unique string for each request
'ts' => Time.now.to_i, # timestamp of the request
'crit' => ['ts', 'nonce'] # critical headers
}
Preventing a replay attack
Fintoc uses the nonce
and ts
timestamp headers in its JWS authentication process to protect against replay attacks and ensure request integrity.
The nonce
string should be a unique, random value and needs to be included in every request, making each signature distinct even if the same data is sent multiple times. Fintoc ensures that each nonce
is used only once, and will reject any request that contains a duplicated nonce
.
The ts
timestamp records when the request was created, and Fintoc’s servers validate that it falls within a 2 minute time window to prevent the processing of outdated requests.
Together, the nonce and timestamp provide robust protection by ensuring that intercepted or tampered requests cannot be reused, safeguarding your integration against malicious activities.
Generate the Signing Input
The signing input for a JWS consists of concatenating the base64url-encoded headers
and the base64url-encoded raw_body
with a period .
between them, both without padding:
# generate the procted section of the jws by base64 encoding the headers without padding
protected_base64 = base64.urlsafe_b64encode(
json.dumps(headers).encode()
).rstrip(b'=').decode()
# generate the payload section of the jws by base64 encoding the raw_body without padding
payload_base64 = base64.urlsafe_b64encode(
raw_body.encode()
).rstrip(b'=').decode()
# generate the signature input by concatenating the encoded protected and payload components
signing_input = f"{protected_base64}.{payload_base64}"
// generate the procted section of the jws by base64 encoding the headers without padding
const protectedBase64 = Buffer.from(JSON.stringify(headers))
.toString('base64url');
// generate the payload section of the jws by base64 encoding the raw_body without padding
const payloadBase64 = Buffer.from(rawBody)
.toString('base64url');
// generate the signature input by concatenating the encoded protected and payload components
const signingInput = `${protectedBase64}.${payloadBase64}`;
# generate the procted section of the jws by base64 encoding the headers without padding
protected_base64 = Base64.urlsafe_encode64(headers.to_json, padding: false)
# generate the payload section of the jws by base64 encoding the raw_body without padding
payload_base64 = Base64.urlsafe_encode64(raw_body, padding: false)
# generate the signature input by concatenating the encoded protected and payload components
signing_input = "#{protected}.#{payload_base64}"
Generate JWS Token Signature
Once you have the signing input ready, you'll create the cryptographic signature using your private key. The process involves:
-
Sign the input using your private key with:
- RSA with PKCS1v15 padding
- Base64URL-encode the resulting signature (without padding)
-
Base64URL-encode the resulting signature (without padding)
# generate the raw signature by signing the signing_input
signature_raw = private_key.sign(
signing_input.encode(),
padding.PKCS1v15(),
hashes.SHA256()
)
# base64 encode the raw signature without padding
signature_base64 = base64.urlsafe_b64encode(signature_raw).rstrip(b'=').decode()
// generate the raw signature by signing the signing_input
const signatureRaw = crypto.createSign('sha256')
.update(signingInput)
.sign({
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PADDING
});
// base64 encode the raw signature without padding
const signatureBase64 = Buffer.from(signatureRaw)
.toString('base64url');
# generate the raw signature by signing the signing_input
signature_raw = private_key.sign(OpenSSL::Digest::SHA256.new, signing_input)
# base64 encode the raw signature without padding
signature_base64 = Base64.urlsafe_encode64(signature_raw, padding: false)
Optional: Verify JWS Token
Some libraries may re-encode JSON payloads with different spacing or key ordering, or change its encoding. To debug the signature, you can inspect the generated token at https://jwt.io to verify its content. We also recommend to double-check that the JWS Token payload is equal to the raw_body
being sent in the http request.
token = f"{protected_base64}.{payload_base64}.{signature_base64}"
print(token)
payload = base64.urlsafe_b64decode(
payload_base64 + '=' * (4 - len(payload_base64) % 4)
)
print(payload) # should be equal to raw_body sent in the http request
const token = `${protectedBase64}.${payloadBase64}.${signatureBase64}`
console.log(token)
const payload = Buffer.from(payloadBase64, 'base64url').toString()
console.log(payload) // should be equal to raw_body sent in the http request
token = "#{protected}.#{payload_base64}.#{signature}"
puts token
payload = Base64.urlsafe_decode64(payload_base64 + '=' * (4 - payload_base64.length % 4))
puts payload # should be equal to raw_body sent in the http request
Construct the Fintoc-JWS-Signature Header
Construct the Fintoc-JWS-Signature
header by concatenating the protected header and signature:
jws_signature_header = f"{protected_base64}.{signature_base64}"
const jwsSignatureHeader = `${protectedBase64}.${signatureBase64}`;
jws_signature_header = "#{protected_base64}.#{signature_base64}"
Complete example
Here's a complete example function that puts it all together (you will have to install the mentioned libraries to try it out).
import base64
import json
import time
import secrets
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
def generate_jws_signature_header(raw_body):
# Read private key
with open('./private_key.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(
f.read(),
password=None
)
# Create headers
headers = {
'alg': 'RS256',
'nonce': secrets.token_hex(16),
'ts': int(time.time()),
'crit': ['ts', 'nonce']
}
# Base64url encode without padding
protected_base64 = base64.urlsafe_b64encode(
json.dumps(headers).encode()
).rstrip(b'=').decode()
payload_base64 = base64.urlsafe_b64encode(
raw_body.encode()
).rstrip(b'=').decode()
signing_input = f"{protected_base64}.{payload_base64}"
# Create signature
signature_raw = private_key.sign(
signing_input.encode(),
padding.PKCS1v15(),
hashes.SHA256()
)
signature_base64 = base64.urlsafe_b64encode(signature_raw).rstrip(b'=').decode()
# Debug output
print(f"Token: {protected_base64}.{payload_base64}.{signature_base64}")
payload = base64.urlsafe_b64decode(
payload_base64 + '=' * (4 - len(payload_base64) % 4)
)
print(f"Payload: {payload.decode()}")
return f"{protected_base64}.{signature_base64}"
body = { ... }
raw_body = json.dumps(body) # the exact payload to be sent in the http request
# signature that must be included in the 'Fintoc-JWS-Signature' request header
jws_signature_header = generate_jws_signature_header(raw_body)
import crypto from 'crypto';
import { readFileSync } from 'fs';
function generateJwsSignatureHeader(rawBody) {
// Read private key
const privateKey = readFileSync('./private_key.pem', 'utf8');
const headers = {
alg: 'RS256',
nonce: crypto.randomBytes(16).toString('hex'),
ts: Math.floor(Date.now() / 1000),
crit: ['ts', 'nonce']
};
const protectedBase64 = Buffer.from(JSON.stringify(headers))
.toString('base64url');
const payloadBase64 = Buffer.from(rawBody)
.toString('base64url');
const signingInput = `${protectedBase64}.${payloadBase64}`;
const signatureRaw = crypto.createSign('sha256')
.update(signingInput)
.sign({
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PADDING
});
const signatureBase64 = Buffer.from(signatureRaw)
.toString('base64url');
// Debug output
console.log(`Token: ${protectedBase64}.${payloadBase64}.${signatureBase64}`);
console.log(`Payload: ${Buffer.from(payloadBase64, 'base64url').toString()}`);
return `${protectedBase64}.${signatureBase64}`;
}
const payload = { ... }
const rawBody = JSON.stringify(payload) // the exact payload to be sent in the http request
// signature that must be included in the 'Fintoc-JWS-Signature' request header
const jwsSignatureHeader = generateJwsSignatureHeader(rawBody)
require 'base64'
require 'openssl'
require 'securerandom'
require 'json'
class JwsSignatureHeaderGenerator
def self.generate(raw_body)
private_key = OpenSSL::PKey::RSA.new(File.read('./private_key.pem'))
headers = {
'alg' => 'RS256',
'nonce' => SecureRandom.hex(16),
'ts' => Time.now.to_i,
'crit' => ['ts', 'nonce']
}
protected = Base64.urlsafe_encode64(headers.to_json, padding: false)
payload_base64 = Base64.urlsafe_encode64(raw_body, padding: false)
signing_input = "#{protected}.#{payload_base64}"
signature_raw = private_key.sign(OpenSSL::Digest::SHA256.new, signing_input)
signature = Base64.urlsafe_encode64(signature_raw, padding: false)
"#{protected}.#{signature}"
end
end
body = { ... }
raw_body = body.to_json # the exact payload to be sent in the http request
# signature that must be included in the 'Fintoc-JWS-Signature' request header
jws_signature_header = JwsSignatureGenerator.generate(raw_body)
Step 4: Add funds to Fintoc
To create Transfers, you need to add funds to your account first. You should see the account to which you need to add funds in your Dashboard.
Step 5: Create Transfer
You can start making real-time transfers once you add funds to your account. Using your test Secret Key and including your JWS Signature, create a Transfer from your backend with the amount, currency, and counterparty that will receive the payment.
Use an Idempotency Key
Fintoc supports idempotency to safely retry Transfers without accidentally performing the same operation twice. When creating a Transfer, use an idempotency key. Then, if a connection error occurs, you can safely repeat the Transfers request without risk of creating a second Transfer.
To perform an idempotent request, provide an Idempotency-Key
header to the request. Learn more about idempotent request in this guide.
Create a Transfer for Mexico 🇲🇽
Here is an example of how to create a Transfer for $590.13 Mexican Pesos:
curl --request POST \
--url https://api.fintoc.com/v1/transfers \
--header 'Authorization: sk_test_9c8d8CeyBTx1VcJzuDgpm4H' \
--header 'Fintoc-JWS-Signature: CNMaYaDGU3ZhFV1ve6p3sAdYXhEklej8DVIAMqIWCkpNmT6Jp7iigcndXwH5q3WQFHiswgIQU5-_-4rV3jKGptCROmEyWPW8_elhYH1apzAyjOjyZ55ygv37xKHzIFhixzAwmXlAv4pfD4lVelYWVNOSN7REA0QJeCy2vKdqZ5cjqCXQ1lkQUlzOE7dpuNoAkhAhAJJ8HaamFKy7Gl7uwmqbIr-dVYv21d_9O7mO26n0gy3zWXD2nJDxU5Mzl2pZd8-sFvUr9Kmp_YkeRMh4bSe0fr1Uc_YgkjpmYUyu7kaxRWTbAdJ3GwqWFMUDiyfhHdzvZPZyU4VkWreimoydMA' \
--header 'Idempotency-Key: 1ebfd86c-a75b-4606-872f-9f1cdd9724ca' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"amount": 59013,
"currency": "mxn",
"comment": "Pago de credito 10451",
"reference_id": "150195",
"counterparty": {
"holder_id": "LFHU290523OG0",
"holder_name": "Jon Snow",
"account_number": "012969123456789120"
},
"metadata": {
"customer_id": "12050123"
}
}
'
Currencies are represented as integers
The Fintoc API represents currencies in its smallest possible units with no decimals (as an integer). That means that an amount of MXN $10.29 gets represented by Fintoc as 1029.
You can read more about currencies here.
In Mexico, the Counterparty object is defined by a minimum of 1 attribute:
Parameter | Description |
---|---|
account_number | Account number |
A successful request response looks like this:
{
"id": "tr_jKaHD105H",
"object": "transfer",
"amount": 59013,
"post_date": null,
"transaction_date": null,
"created_at": "2020-04-17T00:00:00.000Z",
"currency": "mxn",
"comment": "Pago de credito 10451",
"reference_id": "150195",
"receipt_url": null,
"type": "outbound",
"tracking_key": null,
"status": "pending",
"mode": "test",
"account_number": null,
"counterparty": {
"holder_id": "LFHU290523OG0",
"holder_name": "Jon Snow",
"account_number": "012969123456789120",
"type": "clabe",
"type_code": "40",
"institution": {
"id": "40012",
"name": "BBVA MEXICO",
"country": "mx"
}
}
}
Create a Transfer for Chile 🇨🇱
Here is an example to create a transfer of $1869 Chilean Pesos:
curl --request POST \
--url https://api.fintoc.com/v1/transfers \
--header 'Authorization: sk_test_9c8d8CeyBTx1VcJzuDgpm4H' \
--header 'Fintoc-JWS-Signature: CNMaYaDGU3ZhFV1ve6p3sAdYXhEklej8DVIAMqIWCkpNmT6Jp7iigcndXwH5q3WQFHiswgIQU5-_-4rV3jKGptCROmEyWPW8_elhYH1apzAyjOjyZ55ygv37xKHzIFhixzAwmXlAv4pfD4lVelYWVNOSN7REA0QJeCy2vKdqZ5cjqCXQ1lkQUlzOE7dpuNoAkhAhAJJ8HaamFKy7Gl7uwmqbIr-dVYv21d_9O7mO26n0gy3zWXD2nJDxU5Mzl2pZd8-sFvUr9Kmp_YkeRMh4bSe0fr1Uc_YgkjpmYUyu7kaxRWTbAdJ3GwqWFMUDiyfhHdzvZPZyU4VkWreimoydMA' \
--header 'Idempotency-Key: 1ebfd86c-a75b-4606-872f-9f1cdd9724ca' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"amount": 1869,
"currency": "clp",
"comment": "Pago de credito 10451",
"counterparty": {
"holder_id": "771433855",
"holder_name": "Piped Piper SpA",
"account_number": "502955923",
"type": "checking_account",
"institution_id": "cl_banco_de_chile"
},
"metadata": {
"customer_id": "12050123"
}
}
'
In Chile, the Counterparty object is defined by 5 attributes:
Parameter | Description |
---|---|
holder_id | Account holder's RUT |
holder_name | Account holder's name |
account_number | Account number |
type | Type of account. Supported types are checking_account and sight_account . |
institution_id | Fintoc institution id for the bank receiving the bank transfer. You can see the code for each institution here |
A successful request response looks like this:
{
"id": "tr_jKaHD105H",
"object": "transfer",
"amount": 1869,
"post_date": null,
"transaction_date": null,
"currency": "clp",
"comment": "Pago de credito 10451",
"reference_id": null,
"receipt_url": null,
"type": "outbound",
"tracking_key": null,
"status": "pending",
"mode": "test",
"account_number": null,
"counterparty": {
"holder_id": "771433855",
"holder_name": "Piped Piper SpA",
"account_number": "502955923",
"type": "checking_account",
"type_code": null,
"institution": {
"id": "cl_banco_de_chile",
"name": "Banco de Chile",
"country": "cl"
}
}
}
Transfer status
After you create the Transfer, it will have a pending
status. As soon as the transfer is settled, it will change its status to succeeded
.
In case there is a problem with the Transfer, such as the counterparty account doesn't exist or is blocked, the Transfer will change its status to rejected
. You can see all the reasons why a transfer can be rejected here.
Step 6: Monitor transfers status
Fintoc sends a transfer.outbound_succeeded
event when the transfer settles. Use the webhook guide to receive these events and run actions, such as sending a notification email to your customer or logging the transfer in your ERP.
We recommend handling the following events:
Event | Description |
---|---|
transfer.outbound_succeeded | Sent when the transfer successfully settles. |
transfer.outbound_rejected | 🇲🇽 In Mexico: Sent when either Banco de Mexico or the counterparty institution has rejected the transfer. You can see the rejection causes here 🇨🇱 In Chile: Sent when the counterparty institution has rejected the transfer. |
Updated about 5 hours ago