# Quickstart: Create an Event Subscription This quickstart walks you through creating an event subscription, completing the webhook handshake, and receiving your first event. ## Prerequisites Before you begin, make sure you have completed the [Getting Started](/getting-started) guide - you'll need your `CLIENT_ID` and `CLIENT_SECRET`, and a valid access token. You will also need: - A publicly reachable HTTPS endpoint to receive webhooks (you can use [webhook.site](https://webhook.site) for testing) ## Step 1: Obtain an access token Request an access token using the **Client Credentials** flow with the `api` scope: ```bash cURL curl -X POST https://id.aritma.io/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=client_credentials \ -d client_id=$CLIENT_ID \ -d client_secret=$CLIENT_SECRET \ -d scope=api ``` ```json { "access_token": "", "expires_in": 3600, "token_type": "Bearer", "scope": "api" } ``` Use the `access_token` in the `Authorization` header for all subsequent requests: ```http Authorization: Bearer ``` ## Step 2: Prepare your webhook endpoint Before creating a subscription you need a publicly reachable HTTPS endpoint. When the subscription is created, a **validation handshake** will be sent to that endpoint. For quick testing you can use [webhook.site](https://webhook.site) - it gives you a unique URL and shows incoming requests in real time. Tip If you are building your own endpoint, it only needs to return a `200 OK` response for incoming `POST` requests at this stage. The actual handshake is completed by making a `GET` request to a URL provided in the handshake headers (see Step 4). ## Step 3: Create a subscription Send a `POST` request to `/api/subscriptions` with the event types you want to receive and your delivery configuration. The `ResourceUri` header controls the **scope** of events you will receive: | ResourceUri | Scope | | --- | --- | | `/subscriptions/{subscriptionId}` | All events for the subscription | | `/subscriptions/{subscriptionId}/resource-groups/{resourceGroupId}` | All events for resources in a resource group | | `/subscriptions/{subscriptionId}/resource-groups/{resourceGroupId}/providers/{provider}/{resourceType}/{resourceId}` | Only events for a specific spesific resource | Example uri for a bank account: `/subscriptions/b02b04ec-3d99-4228-9d77-768ab396cf3f/resource-groups/companyX/providers/aritma.openbanking/accounts/d2aab6d9fd7a4e6eb99c49ec6e129cb2` ### Required headers | Header | Description | | --- | --- | | `Authorization` | Bearer token obtained in Step 1 | | `ResourceUri` | Defines the scope of events to deliver (see table above) | ### Request body schema Batching behavior The `maxEventsPerBatch` setting controls the delivery format. When set to **1**, each event is delivered as a single JSON object. When set to a value **greater than 1**, events are delivered as a JSON array - even if only one event is in the batch. See the [Event Format](/apis/platform/events/event-format#batched-delivery) page for an example of batched delivery. A successful response returns `201 Created` with the subscription details. The `provisioningState` will be `Pending` until the webhook handshake is completed: ```json { "name": "MyFirstSubscription", "eventTypes": [ "banking.account.transaction.received", "banking.payment.status.updated" ], "delivery": { "url": "https://webhook.site/", "authorizationHeader": "YourSecretKey", "maxEventsPerBatch": 10, "preferredBatchSizeInKiloBytes": 128 }, "expirationDate": "2027-01-01T00:00:00Z", "retryPolicy": { "ttl": "00:10:00", "maxEventDeliveryAttempts": 30 }, "deadletterEnabled": false, "provisioningState": "Pending" } ``` ### Try it out ## Step 4: Complete the webhook handshake Immediately after the subscription is created, a validation request is sent to your webhook endpoint. The request includes these headers: | Header | Description | | --- | --- | | `authorization` | The `authorizationHeader` value you configured (e.g. `YourSecretKey`) | | `webhook-request-callback` | The validation URL you must call to activate the subscription | | `webhook-request-origin` | Origin of the validation request (`eventgrid.azure.net`) | An example handshake request received at your endpoint: ```http POST /your-webhook HTTP/1.1 authorization: YourSecretKey webhook-request-callback: https://rp-westeurope.eventgrid.azure.net:553/eventsubscriptions/myfirstsubscription/validate?id=40B7A954-...&token=Kh2eFzENf... webhook-request-origin: eventgrid.azure.net host: webhook.site ``` You have two alternatives for completing webhook validation: Return headers (preferred) Handle the incoming `OPTIONS` request and return 200 OK along with the required response headers: | Header | Description | | --- | --- | | `WebHook-Allowed-Origin` | Must be either the origin from `WebHook-Request-Origin` (recommended) or `*` to allow all origins. | | `WebHook-Allowed-Rate` | Rate permission in requests per minute. Use a positive integer (for example `120`) or `*` for no rate limit. | Your endpoint should respond with: ```http HTTP/1.1 200 OK WebHook-Allowed-Origin: eventgrid.azure.net WebHook-Allowed-Rate: 120 ``` Callback To activate the subscription using callback validation, perform a `GET` request against the `webhook-request-callback` URL: ```bash cURL curl -X GET "https://rp-westeurope.eventgrid.azure.net:553/eventsubscriptions/myfirstsubscription/validate?id=40B7A954-...&token=Kh2eFzENf..." ``` Requires outbound access on port 553 Port `553` is used as an outbound port for callback validation. If your server uses outbound firewall rules, allow outbound traffic on port `553`. Important The validation URL is time-limited. Complete the handshake promptly after receiving it, or the subscription will remain in `Pending` state and no events will be delivered. ## Step 5: Verify the subscription After completing the handshake, confirm your subscription is active by retrieving it: ```json { "name": "MyFirstSubscription", "eventTypes": [ "banking.account.transaction.received", "banking.payment.status.updated" ], "delivery": { "url": "https://webhook.site/", "authorizationHeader": "YourSecretKey" }, "expirationDate": "2027-01-01T00:00:00Z", "retryPolicy": { "ttl": "00:10:00", "maxEventDeliveryAttempts": 30 }, "deadletterEnabled": false, "provisioningState": "Ok" } ``` The `provisioningState` should now be `Ok`, meaning your subscription is active and events will be delivered to your endpoint. ### Try it out ## What's next? - Learn about the [Event Format](/apis/platform/events/event-format) to understand the structure of delivered events - Enable `deadletterEnabled` to capture failed deliveries for inspection - Check the [API Reference](/apis/platform/events/openapi/events-openapi) for the full set of subscription management endpoints