Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,95 @@ client.files.create(

The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically.

## Webhook verification

Verifying webhook signatures is _optional but encouraged_.

For more information about webhooks, see [the API docs](https://increase.com/documentation/webhooks#events-and-webhooks).

### Parsing webhook payloads

For most use cases, you will likely want to verify the webhook and parse the payload at the same time. To achieve this, we provide the method `client.webhooks.unwrap()`, which parses a webhook request and verifies that it was sent by Increase. This method will raise an error if the signature is invalid.

Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). The `.unwrap()` method will parse this JSON for you into an event object after verifying the webhook was sent from Increase.

```python
from increase import Increase
from flask import Flask, request

app = Flask(__name__)

# You can also configure the webhook secret with any of:
# - The `INCREASE_WEBHOOK_SECRET` environment variable.
# - The `webhook_secret` argument to the Increase client.
# - The `secret` argument to `webhooks.unwrap`
client = Increase()

@app.route("/webhook", methods=["POST"])
def webhook():
request_body = request.get_data(as_text=True)

try:

event = client.webhooks.unwrap(request_body, request.headers, secret='your webhook secret')

if event.type == "account.created":
print("Account created:", event.data)
elif event.type == "account.updated":
print("Account updated:", event.data)
else:
print("Unhandled event type:", event.type)

return "ok"
except Exception as e:
print("Invalid signature:", e)
return "Invalid signature", 400


if __name__ == "__main__":
app.run(port=8000)
```

### Verifying webhook payloads directly

In some cases, you may want to verify the webhook separately from parsing the payload. If you prefer to handle these steps separately, we provide the method `client.webhooks.verify_signature()` to _only verify_ the signature of a webhook request. Like `.unwrap()`, this method will raise an error if the signature is invalid.

Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). You will then need to parse the body after verifying the signature.

```python
import json
from increase import Increase
from flask import Flask, request

app = Flask(__name__)

# You can also configure the webhook secret with any of:
# - The `INCREASE_WEBHOOK_SECRET` environment variable.
# - The `webhook_secret` argument to the Increase client.
# - The `secret` argument to `webhooks.unwrap`
client = Increase()

@app.route("/webhook", methods=["POST"])
def webhook():
request_body = request.get_data(as_text=True)

try:
client.webhooks.verify_signature(request_body, request.headers)

# Parse the body after verification
event = json.loads(request_body)
print("Verified event:", event)

return "ok"
except Exception as e:
print("Invalid signature:", e)
return "Invalid signature", 400


if __name__ == "__main__":
app.run(port=8000)
```

## Handling errors

When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `increase.APIConnectionError` is raised.
Expand Down