Create and commit withdrawals
Request flow of withdrawals.
Once you have completed the setup we can start sending withdrawal requests. The request flow is consists of two parts, the proposal and the commit. The proposal response is a validation of the withdrawal and most importantly contains the estimated onchain transaction fees. To actually trigger the onchain withdrawal take the UUID of the proposal and send a commit request.
Signed JWT
All requests my contain a signed JWT as a bearer token. The JWT contains both a header and a payload, which is combined to be signed by the private key part of the key pair generated. The header will need contain the key id which is the response from uploading the public key, while the payload contains the scope of the request, which in our case it must include external_withdrawal
. See Typescript sample code below, using jose npm package.
See more detailed docs on signing JWT.
import * as jose from 'jose';
import * as fs from 'fs';
const API_KEY_ID = process.env.API_KEY_ID;
async function signJWT(payload: jose.JWTPayload, header: jose.JWTHeaderParameters) {
const privateKeyJson = JSON.parse(fs.readFileSync('./private_key.json', 'utf-8'));
const privateKey = await jose.importJWK(privateKeyJson, 'ES256');
const jwt = await new jose.SignJWT(payload)
.setProtectedHeader(header)
.sign(privateKey);
return jwt;
}
export async generateJWT() {
const payload: jose.JWTPayload = {
aud: 'CJX',
scope: 'read external_withdrawal',
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 3600,
};
const header = {
alg: 'ES256',
kid: API_KEY_ID,
typ: 'JWT'
}
const jwt = await signJWT(payload, header);
return jwt;
}
generateJWT()
function will be used by all subsequent requests.
Create withdraw proposal request
- The
account_number
is the last part of the url when you navigate to your specific crypto account on CoinJar Exchange, for instance it isCJX100040062BTC
forhttps://exchange.coinjar.com/accounts/CJX100040062BTC
- create proposal API reference.
const BASE_URL = 'https://api.exchange.coinjar.com'
async createWithdrawalProposal(): Promise {
const jwt = await generateJWT(); // from previous step
const headers = {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json',
};
const body = {
account_number: 'CJX100040062BTC',
amount: '0.001',
network: 'bitcoin',
address: 'bc1qu99p89zds6nff3zpc05spgju658e3xljlvp0v6'
};
const response = await fetch(`${BASE_URL}/external_crypto_withdrawals`, {
method: 'POST',
headers,
body: JSON.stringify(body)
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
}
return response.json();
}
Response json object contains a uuid
string which is used in the subsequent withdrawal commit request.
Commit withdraw request
- Only the
uuid
from the previous proposal response is need to commit the withdraw with aPATCH
request. - commit request API reference.
const BASE_URL = 'https://api.exchange.coinjar.com'
async commitWithdrawal(uuid: string): Promise {
const jwt = await generateJWT(); // from previous step
const headers = {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json',
};
const response = await fetch(`${BASE_URL}/external_crypto_withdrawalsa/${uuid}/commit`, {
method: 'PATCH',
headers
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
}
return response.json();
}
A successful commit will have a response contain a state
property with transferring
.
Get withdraw request
Once the commit for the withdraw is done you can check the state of the withdraw as it flows through our systems and then broadcasted to the appropriate blockchain. You can poll the below API using uuid
from previous step to get the state of the withdraw. State is a property of the json response of the below API.
- Get exisiting withdrawal API reference.
The states are:
transferring
: Assets are marked to transferred from CoinJar Exchange to CoinJar App.transferred
: Assets have been successfully transferred from CoinJar Exchange to CoinJar App.sending
: Withdraw transaction has been created (passing more checks) but not yet broadcasted to the appropriate blockchain.confirming
: Transaction has been broadcasted but not enough block confirmation yet.confirmed
: A number of block confirmations have passed, this varies depending on the blockchain.
const BASE_URL = 'https://api.exchange.coinjar.com'
async getWithdrawal(uuid: string): Promise {
const jwt = await generateJWT(); // from previous step
const headers = {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json',
};
const response = await fetch(`${BASE_URL}/external_crypto_withdrawalsa/${uuid}`, {
method: 'GET',
headers
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
}
return response.json();
}
Updated 12 days ago