github.com/plutov/paypal/v4@v4.7.1/webhooks.go (about)

     1  package paypal
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  )
    12  
    13  // CreateWebhook - Subscribes your webhook listener to events.
    14  // Endpoint: POST /v1/notifications/webhooks
    15  func (c *Client) CreateWebhook(ctx context.Context, createWebhookRequest *CreateWebhookRequest) (*Webhook, error) {
    16  	req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), createWebhookRequest)
    17  	webhook := &Webhook{}
    18  	if err != nil {
    19  		return webhook, err
    20  	}
    21  
    22  	err = c.SendWithAuth(req, webhook)
    23  	return webhook, err
    24  }
    25  
    26  // GetWebhook - Shows details for a webhook, by ID.
    27  // Endpoint: GET /v1/notifications/webhooks/ID
    28  func (c *Client) GetWebhook(ctx context.Context, webhookID string) (*Webhook, error) {
    29  	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/notifications/webhooks/", webhookID), nil)
    30  	webhook := &Webhook{}
    31  	if err != nil {
    32  		return webhook, err
    33  	}
    34  
    35  	err = c.SendWithAuth(req, webhook)
    36  	return webhook, err
    37  }
    38  
    39  // UpdateWebhook - Updates a webhook to replace webhook fields with new values.
    40  // Endpoint: PATCH /v1/notifications/webhooks/ID
    41  func (c *Client) UpdateWebhook(ctx context.Context, webhookID string, fields []WebhookField) (*Webhook, error) {
    42  	req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), fields)
    43  	webhook := &Webhook{}
    44  	if err != nil {
    45  		return webhook, err
    46  	}
    47  
    48  	err = c.SendWithAuth(req, webhook)
    49  	return webhook, err
    50  }
    51  
    52  // ListWebhooks - Lists webhooks for an app.
    53  // Endpoint: GET /v1/notifications/webhooks
    54  func (c *Client) ListWebhooks(ctx context.Context, anchorType string) (*ListWebhookResponse, error) {
    55  	if len(anchorType) == 0 {
    56  		anchorType = AncorTypeApplication
    57  	}
    58  	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), nil)
    59  	q := req.URL.Query()
    60  	q.Add("anchor_type", anchorType)
    61  	req.URL.RawQuery = q.Encode()
    62  	resp := &ListWebhookResponse{}
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	err = c.SendWithAuth(req, resp)
    68  	return resp, err
    69  }
    70  
    71  // DeleteWebhook - Deletes a webhook, by ID.
    72  // Endpoint: DELETE /v1/notifications/webhooks/ID
    73  func (c *Client) DeleteWebhook(ctx context.Context, webhookID string) error {
    74  	req, err := c.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), nil)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	err = c.SendWithAuth(req, nil)
    80  	return err
    81  }
    82  
    83  // VerifyWebhookSignature - Use this to verify the signature of a webhook recieved from paypal.
    84  // Endpoint: POST /v1/notifications/verify-webhook-signature
    85  func (c *Client) VerifyWebhookSignature(ctx context.Context, httpReq *http.Request, webhookID string) (*VerifyWebhookResponse, error) {
    86  	type verifyWebhookSignatureRequest struct {
    87  		AuthAlgo         string          `json:"auth_algo,omitempty"`
    88  		CertURL          string          `json:"cert_url,omitempty"`
    89  		TransmissionID   string          `json:"transmission_id,omitempty"`
    90  		TransmissionSig  string          `json:"transmission_sig,omitempty"`
    91  		TransmissionTime string          `json:"transmission_time,omitempty"`
    92  		WebhookID        string          `json:"webhook_id,omitempty"`
    93  		Event            json.RawMessage `json:"webhook_event,omitempty"`
    94  	}
    95  
    96  	// Read the content
    97  	var bodyBytes []byte
    98  	if httpReq.Body != nil {
    99  		bodyBytes, _ = io.ReadAll(httpReq.Body)
   100  	} else {
   101  		return nil, errors.New("Cannot verify webhook for HTTP Request with empty body.")
   102  	}
   103  	// Restore the io.ReadCloser to its original state
   104  	httpReq.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
   105  
   106  	verifyRequest := verifyWebhookSignatureRequest{
   107  		AuthAlgo:         httpReq.Header.Get("PAYPAL-AUTH-ALGO"),
   108  		CertURL:          httpReq.Header.Get("PAYPAL-CERT-URL"),
   109  		TransmissionID:   httpReq.Header.Get("PAYPAL-TRANSMISSION-ID"),
   110  		TransmissionSig:  httpReq.Header.Get("PAYPAL-TRANSMISSION-SIG"),
   111  		TransmissionTime: httpReq.Header.Get("PAYPAL-TRANSMISSION-TIME"),
   112  		WebhookID:        webhookID,
   113  		Event:            json.RawMessage(bodyBytes),
   114  	}
   115  
   116  	response := &VerifyWebhookResponse{}
   117  
   118  	req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/verify-webhook-signature"), verifyRequest)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	if err = c.SendWithAuth(req, response); err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	return response, nil
   128  }
   129  
   130  // GetWebhookEventTypes - Lists all webhook event types.
   131  // Endpoint: GET /v1/notifications/webhooks-event-types
   132  func (c *Client) GetWebhookEventTypes(ctx context.Context) (*WebhookEventTypesResponse, error) {
   133  	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks-event-types"), nil)
   134  	q := req.URL.Query()
   135  
   136  	req.URL.RawQuery = q.Encode()
   137  	resp := &WebhookEventTypesResponse{}
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	err = c.SendWithAuth(req, resp)
   143  	return resp, err
   144  }