🪝 Webhooks, States, & Callbacks
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_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
.
Specific on ramp events:
-
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:
-
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
.
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
"timeStamp": "2022-10-26T22:36:41.658Z",
"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
}