Quickstart
This page has everything you need to start sending webhooks with Svix.
Main concepts
In Svix you have three important entities you will be interacting with:
messages
: these are the webhooks being sent. They can have contents and a few other properties.application
(consumer application): this is wheremessages
are sent to. Usually you want to create one application for each user on your platform.endpoint
: endpoints are the URLs messages will be sent to. Each application can have multipleendpoints
and each message sent to that application will be sent to all of them (unless they are not subscribed to the sent event type).
For more information, please refer to the Overview section.
Getting started
Get your authentication token (AuthToken
) from the Svix dashboard.
The Svix libraries automatically infer the correct server URL from the authentication token when using the hosted Svix server. No action needed.
If you are self-hosting the server, you will need to explicitly set the server URL yourself. Please refer to the custom server URL section below.
Sending messages
Creating a consumer application
Each of your users needs an associated consumer application. The easiest way is to create a new application whenever a user signs up. In this section we will use the create application API endpoint to create an application.
You would need the application's ID when sending messages. You can either save the ID returned when creating the application, or set your own unique id (e.g. your user's username or internal database id) in the optional uid
field and use that instead.
Code example:
- JavaScript
- Python
- Rust
- Go
- Java
- Kotlin
- Ruby
- C#
- CLI
- cURL
import { Svix } from "svix";
const svix = new Svix("AUTH_TOKEN");
const app = await svix.application.create({ name: "Application name" });
from svix.api import Svix, ApplicationIn
svix = Svix("AUTH_TOKEN")
app = svix.application.create(ApplicationIn(name="Application name"))
import (
svix "github.com/svix/svix-webhooks/go"
)
svixClient := svix.New("AUTH_TOKEN", nil)
app, err := svixClient.Application.Create(ctx, &svix.ApplicationIn{
Name: "Application name",
})
use svix::api::{ApplicationIn, Svix, SvixOptions};
let svix = Svix::new("AUTH_TOKEN".to_string(), None);
let app = svix
.application()
.create(
ApplicationIn {
name: "Application name".to_string(),
..ApplicationIn::default()
},
None,
)
.await?;
import com.svix.models.ApplicationIn;
import com.svix.models.ApplicationOut;
import com.svix.Svix;
Svix svix = new Svix("AUTH_TOKEN");
ApplicationOut app = svix.getApplication().create(new ApplicationIn().name("Application name"));
import com.svix.kotlin.models.ApplicationIn;
import com.svix.kotlin.models.ApplicationOut;
import com.svix.kotlin.Svix;
val svix = Svix("AUTH_TOKEN")
val applicationOut = svix.application.create(ApplicationIn(name = "Application name"))
require "svix"
svix = Svix::Client.new("AUTH_TOKEN")
application_out = svix.application.create(Svix::ApplicationIn.new({
"name" => "Application name"}))
var svix = new SvixClient("AUTH_TOKEN", new SvixOptions("https://api.svix.com"));
applicationOut = await svix.Application.CreateAsync(
new ApplicationIn(name: "Application name")
);
export SVIX_AUTH_TOKEN='AUTH_TOKEN'
svix application create '{ "name": "Application name" }'
curl -X POST "https://api.svix.com/api/v1/app/" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer AUTH_TOKEN" \
-d '{"name": "Application name"}'
Send a message
We will now send a new message using the create message API endpoint. It accepts an app_id
, which is the application's ID (or custom uid
) from the previous section. In addition, it accepts the following fields (as part the json body):
eventType
: an identifier denoting the type of the event. E.g.invoice.paid
.eventId
: an optional unique ID for the event. This is useful if you want to map each message to unique events on your system.payload
: a JSON dictionary that can hold anything. Its content will be sent as the webhook content.
For example, the following code sends a webhook of type eventType
, with the contents of payload
as the body:
- JavaScript
- Python
- Rust
- Go
- Java
- Kotlin
- Ruby
- C#
- CLI
- cURL
const svix = new Svix("AUTH_TOKEN");
await svix.message.create("app_Xzx8bQeOB1D1XEYmAJaRGoj0", {
eventType: "invoice.paid",
eventId: "evt_Wqb1k73rXprtTm7Qdlr38G",
payload: {
type: "invoice.paid",
id: "invoice_WF7WtCLFFtd8ubcTgboSFNql",
status: "paid",
attempt: 2,
},
});
svix = Svix("AUTH_TOKEN")
svix.message.create(
"app_Xzx8bQeOB1D1XEYmAJaRGoj0",
MessageIn(
event_type="invoice.paid",
event_id="evt_Wqb1k73rXprtTm7Qdlr38G",
payload={
"type": "invoice.paid",
"id": "invoice_WF7WtCLFFtd8ubcTgboSFNql",
"status": "paid",
"attempt": 2
}
)
)
svixClient := svix.New("AUTH_TOKEN", nil)
eventId = "evt_Wqb1k73rXprtTm7Qdlr38G"
svixClient.Message.Create(ctx, "app_Xzx8bQeOB1D1XEYmAJaRGoj0", &svix.MessageIn{
EventType: "invoice.paid",
EventId: *svix.NullableString(&eventId),
Payload: map[string]interface{}{
"type": "invoice.paid",
"id": "invoice_WF7WtCLFFtd8ubcTgboSFNql",
"status": "paid",
"attempt": 2,
},
})
let svix = Svix::new("AUTH_TOKEN".to_string(), None);
svix.message()
.create(
"app_Xzx8bQeOB1D1XEYmAJaRGoj0".to_string(),
MessageIn {
event_type: "invoice.paid".to_string(),
event_id: Some("evt_Wqb1k73rXprtTm7Qdlr38G".to_string()),
payload: json!({
"type": "invoice.paid",
"id": "invoice_WF7WtCLFFtd8ubcTgboSFNql",
"status": "paid",
"attempt": 2
}),
..MessageIn::default()
},
None,
)
.await?;
Svix svix = new Svix("AUTH_TOKEN");
svix.getMessage().create("app_Xzx8bQeOB1D1XEYmAJaRGoj0",
new MessageIn()
.eventType("invoice.paid")
.eventId("evt_Wqb1k73rXprtTm7Qdlr38G")
.payload("{" +
"\"type\": \"invoice.paid\"," +
"\"id\": \"invoice_WF7WtCLFFtd8ubcTgboSFNql\"," +
"\"status\": \"paid\"," +
"\"attempt\": 2" +
"}"));
val svix = Svix("AUTH_TOKEN")
svix.message.create("app_Xzx8bQeOB1D1XEYmAJaRGoj0",
MessageIn(
eventType = "invoice.paid",
payload = mapOf<String, Any>(
"type" to "invoice.paid",
"id" to "invoice_WF7WtCLFFtd8ubcTgboSFNql",
"status" to "paid",
"attempt" to 2
),
eventId = "evt_Wqb1k73rXprtTm7Qdlr38G"))
svix = Svix::Client.new("AUTH_TOKEN")
svix.message.create("app_Xzx8bQeOB1D1XEYmAJaRGoj0",
Svix::MessageIn.new({
"event_type" => "invoice.paid",
"payload" => {
"type": "invoice.paid",
"id" => "invoice_WF7WtCLFFtd8ubcTgboSFNql",
"status" => "paid",
"attempt" => 2
},
"event_id" => "evt_Wqb1k73rXprtTm7Qdlr38G"}))
var svix = new SvixClient("AUTH_TOKEN", new SvixOptions("https://api.svix.com"));
await svix.Message.CreateAsync("app_Xzx8bQeOB1D1XEYmAJaRGoj0", new MessageIn(
eventType: "invoice.paid",
payload: new {
type = "invoice.paid",
id = "invoice_WF7WtCLFFtd8ubcTgboSFNql",
status = "paid",
attempt = 2
},
eventId: "evt_Wqb1k73rXprtTm7Qdlr38G"
));
export SVIX_AUTH_TOKEN="AUTH_TOKEN"
svix message create app_Xzx8bQeOB1D1XEYmAJaRGoj0 '{ "eventType": "invoice.paid", "eventId": "evt_Wqb1k73rXprtTm7Qdlr38G", "payload": { "type": "event.type", "id": "invoice_WF7WtCLFFtd8ubcTgboSFNql", "status": "paid", "attempt": 2 } }'
curl -X POST "https://api.svix.com/api/v1/app/app_Xzx8bQeOB1D1XEYmAJaRGoj0/msg/" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer AUTH_TOKEN" \
-d '{"eventType": "invoice.paid", "eventId": "evt_Wqb1k73rXprtTm7Qdlr38G", "payload": {"type": "event.type", "id": "invoice_WF7WtCLFFtd8ubcTgboSFNql", "status": "paid", "attempt": 2}}'
Including the event type in the payload
Webhook consumers often consume multiple event types using the same endpoint. To enable them to be able to differentiate different events, it's common practice to include the event type in the webhook's payload. Svix, however, doesn't automatically inject the event type into the payload, in order to give our customers full control over the content and structure of the payloads they send.
Most commonly people include the event type in the payload as a top-level key called type
, event_type
, or eventType
, but it's up to you how you want to call it.
Idempotency
Svix supports idempotency for safely retrying requests without accidentally performing the same operation twice. This is useful when an API call is disrupted in transit and you do not receive a response.
For more information, please refer to the idempotency section of the docs.
Note: while the eventId
can potentially be used to enforce short-term uniqueness (similar to idempotency), it's recommended to use the idempotency mechanism when needed rather than relying on eventId
checks.
Add webhook endpoints
In the example above we showed how to send messages, though these messages were not sent to any specific URLs. In order for them to be sent, we need to add endpoints. This is what this section is about.
You can use the Svix Play webhook debugger and the Svix CLI to inspect, test and debug your webhooks during development.
Using the Application Portal
Svix offers a pre-build application portal. With one API call, you can give your users access to this UI and they can then add their own endpoints themselves. App portal access is based on short-lived sessions using special magic links. Your customers don't need a Svix account, and they don't even need to know that Svix exists.
More on that in the application portal docs.
Using the API
In addition to the App Portal, you can also use our API to add endpoints to your applications. To do so, you will use the create endpoint API.
For example:
- JavaScript
- Python
- Rust
- Go
- Java
- Kotlin
- Ruby
- C#
- CLI
- cURL
const svix = new Svix("AUTH_TOKEN");
await svix.endpoint.create("app_Xzx8bQeOB1D1XEYmAJaRGoj0", {
url: "https://api.example.com/svix-webhooks/",
version: 1,
description: "My main endpoint",
});
svix = Svix("AUTH_TOKEN")
svix.endpoint.create(
"app_Xzx8bQeOB1D1XEYmAJaRGoj0",
EndpointIn(
url="https://api.example.com/svix-webhooks/",
version=1,
description="My main endpoint",
)
)
svixClient := svix.New("AUTH_TOKEN", nil)
svixClient.Endpoint.Create(ctx, "app_Xzx8bQeOB1D1XEYmAJaRGoj0", &svix.EndpointIn{
Url: "https://api.example.com/svix-webhooks/",
Version: 1,
Description: svix.String("My main endpoint"),
})
let svix = Svix::new("AUTH_TOKEN".to_string(), None);
svix.endpoint()
.create(
"app_Xzx8bQeOB1D1XEYmAJaRGoj0".to_string(),
EndpointIn {
url: "https://api.example.com/svix-webhooks/".to_string(),
version: 1,
description: Some("My main endpoint".to_string()),
..EndpointIn::default()
},
None,
)
.await?;
Svix svix = new Svix("AUTH_TOKEN");
svix.getEndpoint()
.create("app_Xzx8bQeOB1D1XEYmAJaRGoj0",
new EndpointIn()
.url("https://api.example.com/svix-webhooks/")
.version(1)
.description("My main endpoint"));
val svix = Svix("AUTH_TOKEN")
val endpointOut =
svix.endpoint.create("app_Xzx8bQeOB1D1XEYmAJaRGoj0",
EndpointIn(
url = URI("https://api.example.com/svix-webhooks/"),
version = 1,
description = "My main endpoint"))
svix = Svix::Client.new("AUTH_TOKEN")
endpoint_out =
svix.endpoint.create("app_Xzx8bQeOB1D1XEYmAJaRGoj0",
Svix::EndpointIn.new({
"url" => "https://api.example.com/svix-webhooks/",
"version" => 1,
"description" => "My main endpoint"}))
var svix = new SvixClient("AUTH_TOKEN", new SvixOptions("https://api.svix.com"));
endpointOut = await svix.Endpoint.CreateAsync(new EndpointIn(
url: "https://api.example.com/svix-webhooks/",
version: 1,
description: "My main endpoint"
));
export SVIX_AUTH_TOKEN="AUTH_TOKEN"
svix endpoint create app_Xzx8bQeOB1D1XEYmAJaRGoj0 '{ "url": "https://api.example.com/svix-webhooks/", "version": 1, "description": "My main endpoint" }'
curl -X POST "https://api.svix.com/api/v1/app/app_Xzx8bQeOB1D1XEYmAJaRGoj0/endpoint/" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer AUTH_TOKEN" \
-d '{"url": "https://api.example.com/svix-webhooks/", "version": 1, "description": "My main endpoint"}'
The version number is an integer signifying the current version of the API. You can set it to 1
if you haven't started versioning your API yet.
Using Svix in a stateless manner
You can use Svix in a completely stateless manner, without having to store any Svix identifiers (or anything else) in your own database; you can do it by utilizing UID
s. If you set a UID
on an application, endpoint, or any other entity, you can use this UID
interchangeably with its ID
anywhere in the API.
For more information, please refer to the section about UID
s in the overview.
Consuming webhooks documentation
Please refer to the consuming webhooks section for information you can share with your customers on how to easily consume webhooks, and how to use the application portal.
Common Usage Examples
The above should give you everything you need to know in order to get started with Svix. However, we've gathered examples of some of the more common ways people use the Svix API in order to make it even easier for you to get started and follow the best practices.
For more information please refer to the common usage examples section.
Custom server URL
Starting from version 0.64.0, the libs automatically infer the correct server URL from the authentication token (for tokens created from August 2022 onwards).
If you are using old tokens, or a non-standard server URL, you may need to set the URL explicitly in the library based on your chosen environment and as shown in the "API Access" page in the dashboard.
- JavaScript
- Python
- Rust
- Go
- Java
- Kotlin
- Ruby
- C#
- CLI
- cURL
import { Svix } from "svix";
const svix = new Svix("AUTH_TOKEN", { serverUrl: "THE_SERVER_URL" });
from svix.api import Svix, SvixAsync, SvixOptions
svix = Svix("AUTH_TOKEN", SvixOptions(server_url="THE_SERVER_URL"))
# Or use the async variants
svix = SvixAsync("AUTH_TOKEN", SvixOptions(server_url="THE_SERVER_URL"))
import (
svix "github.com/svix/svix-webhooks/go"
)
serverUrl, _ := url.Parse("THE_SERVER_URL")
svixClient := svix.New("AUTH_TOKEN", &svix.SvixOptions{
ServerUrl: serverUrl,
})
use svix::api::{ApplicationIn, Svix, SvixOptions};
let svix = Svix::new("AUTH_TOKEN".to_string(), SvixOptions {
server_url: "THE_SERVER_URL".to_string(),
..SvixOptions::default()
});
import com.svix.Svix;
Svix svix = new Svix("AUTH_TOKEN", new SvixOptions().serverUrl("THE_SERVER_URL"));
import com.svix.kotlin.Svix;
val svix = Svix("AUTH_TOKEN", SvixOptions("THE_SERVER_URL"))
require "svix"
svix = Svix::Client.new("AUTH_TOKEN", Svix::SvixOptions.new(false, "THE_SERVER_URL"))
using Svix;
var svix = new SvixClient("AUTH_TOKEN", new SvixOptions("THE_SERVER_URL"));
export SVIX_AUTH_TOKEN='AUTH_TOKEN'
export SVIX_SERVER_URL='THE_SERVER_URL'
svix application create '{ "name": "Application name" }'
# Just replace the URL below
curl -X POST "https://api.svix.com/api/v1/app/" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer AUTH_TOKEN" \
-d '{"name": "Application name"}'
Closing words
That's it! There are only three API calls you should really care about. Creating applications (i.e users), sending messages, and giving your users access to the App Portal. All of them are covered here.