Search code examples
node.jstypescriptwebhookscoinbase-api

Coinbase webhook: Property 'metadata' does not exist on type 'CheckoutResource'


I want to access the metadata after a payment has succeeded with coinbase by listening to the charge:confirmed event. In the example for a webhook payload (https://docs.cloud.coinbase.com/commerce/docs/webhooks-events) the event.data has a metadata property from which I should be able to retrieve the metadata that is provided when creating the charge.

export const webhook = async (req: Request, res: Response) => {
  try {
    const rawBody = req.rawBody;
    const signature: string = req.headers["x-cc-webhook-signature"] as string;

    const event = Webhook.verifyEventBody(
      rawBody,
      signature,
      process.env.COINBASE_WEBHOOK_KEY
    );
    if (event.type === "charge:confirmed") {
      //TODO
      // make database entry and send nodemailer mail to notify user of purchase
      const metadata = event.data.metadata;
    }

    res.status(201).json({ msg: "Success" });
  } catch (error) {
    console.log(error.message);
    res.status(400).json({ msg: "An error occured" });
  }
};

When trying to access the metadata,

const metadata = event.data.metadata;

I get a typescript error:

Property 'metadata' does not exist on type 'ChargeResource | CheckoutResource'. Property 'metadata' does not exist on type 'CheckoutResource'

How can I get the metadata? I cannot log the event.data since the coinbase API does not provide a way to test their webhooks unless you do real transactions.


Solution

  • Webhook.verifyEventBody() method returns an Event which extends EventResource.

    interface Event extends EventResource {}
    
    interface EventResource<T = ChargeResource | CheckoutResource> {
      //...
    
      data: T;
    }
    interface ChargeResource extends BaseCharge {
      //...
      resource: 'charge';
      metadata: KeyVal;
    }
    interface CheckoutResource extends BaseCheckout {
      //...
      resource: 'checkout';
    }
    

    Only the ChargeResource interface has the metadata field. The CheckoutResource interface does not have it.

    You should narrow down the type to ChargeResource for event.data by checking event.data.resource.

    const event = Webhook.verifyEventBody('rawBody', 'signature', 'sharedSecret');
    if (event.data.resource === 'charge' && event.type === 'charge:confirmed') {
      const metadata = event.data.metadata;
    }
    

    package versions

    @types/coinbase-commerce-node: 1.0.6
    coinbase-commerce-node: 1.0.4