API endpoint for fees

Is it just me or does this Advanced Trade API feel way worse than Coinbase Pro? It just feels unfinished and badly implemented.

For example, I’m looking for the API endpoint to tell me the current maker/taker fees for a user and I can’t seem to find it in the documentation. Coinbase Pro and every other exchange has it.

It seems ridiculous to be forcing people to migrate from Coinbase Pro to Advanced Trade when it’s a huge step down. At very least they should have matched the API functionality!

Does anyone know if there is an API endpoint to retrieve the user’s current fee rates?


I would like the equivalent to this:

1 Like

Did you look at this?:

1 Like

I missed that one but thanks for the link. I’ll take a look.

It’s not what I’m looking for. This is just a list of fees per transaction. I am looking for the current maker/taker fee tier like you get with /fees with Coinbase Pro.

This is also asking for a “start date” and “end date” but it doesn’t say what format it should be in:

It just says: start_date date-time

Any idea what that date-time format should be?

This can’t be the only way to get the fees.

1 Like

I don’t use use start_date and/or end_date. I think taker_fee_rate and maker_fee_rate is what you are looking for.

This also shows that it is right API to get fees.

@muktupavels is correct. The transaction summary endpoint will return an object like this:

  total_volume: 26214.767578125,
  total_fees: 77.39559173583984,
  fee_tier: {
    pricing_tier: '',
    usd_from: '10000',
    usd_to: '50000',
    taker_fee_rate: '0.004', <----------- TAKER FEE
    maker_fee_rate: '0.0025' <----------- MAKER FEE
  margin_rate: null,
  goods_and_services_tax: null,
  advanced_trade_only_volume: 26214.767578125,
  advanced_trade_only_fees: 77.39559173583984,
  coinbase_pro_volume: 0,
  coinbase_pro_fees: 0

The maker and taker fee rates will be in the fee_tier property. They are shown as a percentage on the site, so you have to shift the decimal 2 places to the right if you want it to match. For example, for me you can see a fee tier of 0.004, but on the Coinbase website shows it as 0.4%. It’s not a fee for any particular transaction.

The language they use is maybe a bit confusing. It’s not a summary of each transaction you’ve made. It’s more like a summary of your entire account, in relation to your transaction activity. So it will tell you how much volume in total you’ve traded, how many total fees you’ve paid, etc.

As far as the start/end dates go, I never use them either. When I call the endpoint it gives me a summary of the last 30 days. My assumption would be you could put in a start and end date, and get a summary of a particular timeframe. Haven’t tested that though, so I’m not 100% sure. Wish the documentation were a little more clear on it.


Thanks, did you need to pass any params for this or just the plain GET to the end point?


Are these optional and I’m not passing any of them?

start_date date-time
end_date date-time
user_native_currency string String of the users native currency, default is USD
product_type string
Type of product SPOT

I’m getting a error 403 and I’m just trying to figure out why. I checked they I have the wallet:transactions:read permission.

I got a 401 is I do call this:

I don’t think it was in the docs at the time, but I did need to pass user_native_currency: 'USD' as a param, as it was not defaulting to anything and was returning an error. Not sure if that’s still required, but it hasn’t hurt anything so I still have it in my code and it’s still working.

Also worth noting that you pass the param in the body of the request, not the url.

When you say you are passing it in the body of your request do you have an example? It seems strange for them to do this and it’s opposite of what the documentation example shows.

I tried this but it doesn’t work…

    body = (request.body or b"").decode()
    message = f"{timestamp}{request.method}{request.path_url}{body}"

Which results in the message looking like this:

    1679676973GET/api/v3/brokerage/transaction_summary{"user_native_currency": "GBP"}

@jmicko, I’ve updated my requests.get to look like this:
resp = requests.get(self._api_url + uri, params=payload, auth=self)

It still results in a message before signing that looks like this:

For a GET the params are passed in the URL. I’m not quite sure what you mean about passing the param in the body of the request. That would normally be what a POST looks like. This isn’t a POST right?

Do you have an example of what you have done that works?

I’m still getting a 401.

You’re right, my bad. I read my own code wrong lol. The params do go in the url.

One thing I’m noticing now is that your message has the params in it.

You shouldn’t have them in there when you sign the message. So in that example, you should be signing a message that looks like this: 1679732266GET/api/v3/brokerage/transaction_summary

I have a javascript example, idk if that helps. It’s taken from a much larger class object so I’ll just paste the relevant parts and you can maybe work it out.

  class Coinbase {
  constructor(key, secret) {
    if (!secret?.length || !key?.length) {
      throw new Error('Coinbase is missing mandatory key and/or secret!');
    this.key = key;
    this.secret = secret;
    this.WS_API_URL = 'wss://advanced-trade-ws.coinbase.com';
    this.ws = null;
    this.products = null;

  async getTransactionSummary(params) {
    return new Promise(async (resolve, reject) => {
      try {
        // data should just be blank
        const data = null;
        const API = {
          url: `https://coinbase.com/api/v3/brokerage/transaction_summary`,
          path: "/api/v3/brokerage/transaction_summary",
          method: 'GET',
        // sign the request
        const options = this.signRequest(data, API);
        // add params, if any
        if (params) { this.addParams(options, params) };
        // make the call
        let response = await axios.request(options);
      } catch (err) {

  // used for signing all REST requests
  signRequest(data, API) {
    // convert the data to JSON, if any
    const body = data ? JSON.stringify(data) : '';
    // get the timestamp
    const timestamp = Math.floor(Date.now() / 1000).toString();
    // build the message string
    const message = timestamp + API.method + API.path + body;
    // sign the message
    const sig = CryptoJS.HmacSHA256(message, this.secret).toString();
    // build the options object to return to the requester function
    const options = {
      method: API.method,
      timeout: 10000,
      url: API.url,
      headers: {
        Accept: 'application/json',
        'cb-access-key': this.key,
        'cb-access-sign': sig,
        'cb-access-timestamp': timestamp
      data: data
    return options;

  // add params to url after signing but before calling
  addParams(options, params) {
    // this function is only called if there are params, so add a ? to the url string
    options.url = options.url + `?`;
    // Iterate over each object key/value pair, adding them to the url
    Object.keys(params).forEach(key => {
      // add new param
      options.url += `${key}=${params[key]}&`;
    // cut off the last & symbol
    options.url = options.url.slice(0, -1)

Thanks, I actually got this working already but thanks for the reply.

The problem was as you say, including the query string params in the message to sign.

1 Like

@michael.whittle Your github repo is very helpful! It seems that the fee rate is applied to the quote based on the example they have in the doc for ‘commission’ field in Fills endpoint, can you shed some light? (I am heading to your github to check there as well)
Thank you

Hi, sorry I just saw your comment. Did you manage to find what you were looking for?

Hi, I was trying to understand in which asset is the fee deducted and the unit of the ‘commission’ and other fee information from the API

Also, when you receive an order status, do you get all the configurations with None? or only the configuration of the order?

Thank you