🪝 Webhooks, States, & Callbacks
How you know what we know
States
Koywe Transactions follow a (mostly) linear path: they get created, they get paid, and they get delivered. All this is notified via webhooks (see below) or is returned when you call our APIs to follow up on an order.
The possible states for an order are:
-
WAITING
: The order has been created and is waiting to be paid. -
PENDING
: The order has been paid and it’s queued for execution. -
EXECUTING
: The order is being executed. ie: The transaction is being sent to the blockchain or the bank. -
IN_PROGRESS
: Funds, either crypto or fiat, are on their way to their destination. -
INVALID_WITHDRAWALS_DETAILS
: Only valid for off ramps. The banking details were incorrect and the destination bank has rejected the transfer. -
REJECTED
: The order has been rejected by the user or the payment processor. -
DELIVERED
: The funds, either crypto or fiat, have been delivered successfully.
Webhooks
To make you integration easier, we have enabled ways to alert you when something happens or to define validation services before executing transactions.
You can setup a URL to recibe requests every time an event is triggered for a transaction. possible events are:
-
payment_created
: order is created, Koywe awaits the payment in either fiat or crypto. The order shows aWAITING
state. -
payment_received
: order is paid. Koywe confirms the payment successfully and will deliver theamountOut
. Order state will bePENDING
. -
payment_rejected
: order is rejected. Something happened and the order has been rejected. This event is NOT sent for wire transfers and it’s usually due to an error on cancellation on the user’s part. Order state will beREJECTED
. -
payment_rejected_by_compliance
: the order is rejected. Something happened during the compliance or risk analysis, and the order was rejected. This event is NOT sent for wire transfers and is usually due to an issue with the user’s information. The order status will beREJECTED
. -
payment_expired
: order is expired. Only sent for wire transfers. The user took too long to transfer or Koywe couldn’t detect the payment on time. Another order or quote should be created to secure a price. Order state will beREJECTED
. -
payment_received_modified_order_amount:
This webhook event is triggered when an order is modified due to a received bank deposit. Currently, this event only applies to bank transfers made in Peru. When a user makes a bank deposit, the deposited amount may be greater or less than the original order amount. In this case, the order is automatically adjusted to the received amount. To modify the order, a new quote is generated based on the received amount, and the order is updated with this new quote. This way, the order will reflect the correct amount after the bank deposit. This event also sends an object where the original order (originalOrder) and the recalculated order (orderAdjustedByBankIncome) will be received.
Specific on ramp events (“currency-crypto”):
-
crypto_tx_sent
: crypto transaction is sent after fiat payment is confirmed. Order state will beIN_PROGRESS
. -
crypto_delivered
: crypto transaction nis confirmed by the blockchain. Order state will beDELIVERED
. -
crypto_tx_failed
: crypto transaction failed. This shouldn’t happen, but does in some minor cases (1 out of 10 thousand). If it were to happen, we would retry the transaction. Order state will beREJECTED
.
Specific off ramp events (“crypto-currency”):
-
fiat_sent
: fiat transfer is sent from Koywe’s account. Order state will beIN_PROGRESS
. -
fiat_delivered
: fiat is delivered, according to Koywe’s bank. Order state will beDELIVERED
. -
invalid_withdrawals_details
: the fiat transfer was attempted, but the bank rejected the transaction because the account or the owner of the account didn’t match existing records. There’s a special endpoint to correct these details. Check out the API docs for more information. Order state will beINVALID_WITHDRAWALS_DETAILS
. -
refund_started
: The request for a crypto refund has been initiated due to errors in the fiat transfer details. Order state will beREFUND_STARTED
. -
refund_in_progress
: The process of sending the crypto refund has begun. Order state will beREFUND_IN_PROGRESS
. -
refund_delivered
: The crypto refund has been successfully sent and confirmed. Order state will beREFUND_DELIVERED
.
Additionally, you weill be able to defined a secret
to validate our requests.
Using this secret, we encrypt the request parameters and add the hash for you to
verify:
const signature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
Example of a request:
{
"eventName": "crypto_delivered", // event, from the list above
"orderId": "5a3288ea-0bd4-44d2-af11-aae1f88bbd61", // order id
"orderType": "currency-crypto", // This attribute specifies the type of order, which can be either OnRamp ("currency-crypto") or OffRamp ("crypto-currency").
"externalId": "34ae1f88bbd6", // This attribute is returned only if the 'externalId' was specified during the order creation process.
"timeStamp": "2022-10-26T22:36:41.658Z",
"signature": "ed40d34ab7a587cf1a16338a16cc7765ae4420936677482bb33f5f738e4f7189" // hash
}
KYC Webhooks
If you’re using our KYC process, you will also receive webhook notifications when a user starts and completes a KYC verification. For now, these will be sent to the same url as the operational webhooks.
-
verification_started
: The user clicks the button to start the ID verification. The KYC status of the user will go fromnotVerified
toprocessing
. -
verification_inputs_completed
: User has finished uploading the information and submitting the forms, so we start processing all the data. The KYC status of the user will remain inprocessing
. -
verification_completed
: We have finished analysing the user’s data and have a result. The KYC status of the user will go to eitherverified
orreviewNeeded
. For the latter, our compliance team has to complete a manual review to bring the user toverified
orrejected
. -
verification_expired
: The user hasn’t finished within 30 minutes of starting the process. The KYC status will go back tonotVerified
.
Example of a request:
{
"eventName": "verification_started", // event, from the list above
"orderId": "KYC_EVENT",
"timeStamp": "2022-10-26T22:36:41.658Z",
"data": "guillermo@koywe.com",
"signature": "ed40d34ab7a587cf1a16338a16cc7765ae4420936677482bb33f5f738e4f7189" // hash
}
Authentication Callback
You can setup a URL to your API for us to confirm a user is allowed to operate in your specific context. Every time a user wants to buy, sell, or check private information associated to your environment, we will send a request to this URL before proceeding.
Our platform assumes your API will respond something that looks like a boolean and supports many authentication methods.
We will default to use the POST method. If you want other methods, please let us know.
An example using pseudo code:
// user buys crypto
const createOrder (payload) {
if (!validUser(payload.email)) throw new Error('user not allowed');
else continue
}
// we check with your API before proceeding
const validUser(email) {
const payload = { email }
const headers = { 'Authorization': 'Bearer superJWT' }
const { data } = await axios.post(urlExternalAPI, payload, { headers })
reurn data
}
Webhooks Document number update
If you made a document number change, we will perform an asynchronous validation of the person’s data. The results of that validation will be sent through webhooks
UPDATE_DOCUMENT_NUMBER
: After a data validation, you will receive an event with this name where there will be a confirmation message, or an error message because there was a discrepancy in the user’s data.
-
document_number_sucessfully_updated
: The data verification process finished with success and the document number has been updated. -
document_number_failed_to_update
: There was an error during the verification flow, ie: “Account does not have any personal info”, “Account not found”, “There is incompatible personal info between the account and metamap”.
Example of a request:
{
"eventName": "document_number_sucessfully_updated", // Or "document_number_failed_to_update" if failed,
"orderId": "UPDATE_DOCUMENT_NUMBER",
"timeStamp": "2022-10-26T22:36:41.658Z",
"data": {
"email": {{email}},
"message": {{error or success message}},
"details": "The date of birth in the account ({date}) doesn't match the one in metamap ({date}). || Name mismatch detected. Expected: {name}. Found: {name}"
},
"signature": "ed40d34ab7a587cf1a16338a16cc7765ae4420936677482bb33f5f738e4f7189" // hash
}
Webhooks Deposits
This event will notify the clients if a deposit arrives to our system from a user that has no current orders.
NEW_DEPOSIT_REGISTERED
: When processing the deposit received, and associating it to a user, if this user has no current orders it will remain in his balance, at this moment this event will be fired.
deposit_without_order
.
Example of a request:
{
"eventName": "deposit_without_order",
"orderId": "NEW_DEPOSIT_REGISTERED",
"timeStamp": "2024-06-07T16:17:54.258Z",
"data": {
"documentNumber": "{{documentNumber}}",
"currency": "ARS",
"clientId": "65c4ed085f193b99de04f061",
"accountBalanceAmount": 50000,
"email": "{{email}}"
},
"signature": "ae0e02ae78ef00c5b2c623d3abf41c2785434af0bbba55e2371b1fa38c6b63f3"
}