Managing your integration
Set up a custom integration through the API.
Use the API to create an event source and define the events it sends. To set this up in the VYG app instead, follow the quickstart. The app's pages are described in Data sources in the app.
You will need a vyg_ba_ API key with the providers:read and providers:write scopes, or a
signed-in (OAuth) token with the same scopes. See API keys. The provider
endpoints are documented in the Integrations reference.
Key terms
- A provider is a source of events. It has a webhook URL and a signing secret. The app calls it a data source, and its ID is the Data source ID on the data source's Settings tab.
- An event definition describes a single kind of event that provider sends: its name, the shape of its payload, and how to find the customer inside it. The app calls it an event.
- A type matcher matches incoming events to their definitions. In the app, it is the answer to What does (your tool) call this event? on the event's Details section.
1. Create a provider
curl -sS -X POST https://api.vyg.app/v1/providers \
-H "Authorization: Bearer $VYG_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "My Store" }'The response is the created provider itself, not wrapped in data:
{
"id": "3f0f8a1e-...",
"key": "my_store",
"name": "My Store",
"lookup_id": "ezLUu3AC28uEa3qb4tTE4",
"source_template_key": null,
"is_enabled": true,
"settings": {},
"api_key": "vyg_ba_...",
"webhook_secret": "whsec_...",
"webhook_url": "https://<hook-host>/custom/ezLUu3AC28uEa3qb4tTE4"
}api_key and webhook_secret are returned exactly once, in this response.
Save them in your secret manager before leaving this response.
api_key is a vyg_ba_ API key with the providers:read and providers:write
scopes. It is issued only when you create the provider with a signed-in (OAuth)
token that has the keys:manage scope; with an API key or any other token,
api_key is null, since creating a key requires sign-in. Use it to
manage this integration over api.vyg.app; it appears under
Settings → Data API Keys and is revoked there like any other key.
Replace signing secret in the app replaces only the webhook secret; it never issues or
revokes an API key. Webhook delivery uses webhook_secret, not api_key.
webhook_url is where you will post your events, signed with webhook_secret.
If your supplied key is already taken, the request returns 409. Omit key and we derive one from name and
make it unique for you.
A brand can have up to 25 providers. Creating one more answers 409 with the
code limit_reached.
GET /v1/providers returns { "data": [], "next_cursor": null } until the brand has a provider. It
returns every provider in one page, so next_cursor is always null. Reading, creating and updating a
single provider return the provider itself; the path parameter is provider_id
(GET /v1/providers/{provider_id}).
2. Register an event definition
Say your platform sends an order like this:
{
"type": "order.created",
"id": "ord_1029",
"email": "ada@example.com",
"created_at": "2026-07-14T12:00:00Z",
"total": 84.5
}Describe it. The create response is the event definition itself, with id, provider_id, type,
name, description, payload_schema, identifier_mappings, schema_version, source_template_key,
is_enabled, created_at and updated_at:
curl -sS -X POST https://api.vyg.app/v1/providers/3f0f8a1e-.../event-definitions \
-H "Authorization: Bearer $VYG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "new_order",
"name": "New Order",
"payload_schema": {
"type": "object",
"properties": {
"id": { "type": "string" },
"email": { "type": "string" },
"created_at": { "type": "string" },
"total": { "type": "number" }
},
"required": ["id", "email"]
},
"identifier_mappings": {
"external_id_path": ["id"],
"email_path": ["email"],
"received_at_path": ["created_at"]
}
}'payload_schema defines the accepted event payload using JSON Schema.
identifier_mappings identifies the event's entity and contact. external_id_path
selects a stable entity ID, such as an order ID. Provide at least one of email_path
or phone_path; an event without either contact channel is rejected. Email alone is
accepted and can trigger email flows; SMS and agent flows still need a phone number.
Each is a list of candidate paths in dot notation (id,
customer.email, data.items.0.sku) resolved against your event payload. They are not
JSONPath, so there is no leading $.. The first path that resolves to a non-empty value wins.
The app shows these lists as Use the first one that has a value.
The event definition routes cover the payload schema and the identifier mappings. The Order details and Where it came from mappings are set in the app's event editor. Whether an event counts as a sale is set by our team; ask your account manager.
3. Point your events at the definition
Your payload carries "type": "order.created", but the definition is called
new_order. A type matcher connects them. The same settings update also
tells us where the delivery ID is, which is a request mapping:
curl -sS -X PATCH https://api.vyg.app/v1/providers/3f0f8a1e-... \
-H "Authorization: Bearer $VYG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"settings": {
"type_matchers": {
"new_order": { "from": "body", "key": "type", "equals": "order.created" }
},
"request_mapping": {
"event_id": { "from": "body", "path": "id" }
}
}
}'This matcher means: an event whose body field type equals order.created is a
new_order.
The request_mapping.event_id is required for a flat payload like this one. By
default we expect the envelope { "type": ..., "event_id": ..., "data": {...} } and
read the id from event_id; a post without one is rejected. Your payload puts the
id at the root as id, so the mapping points there (from: "body", path: "id").
Leaving payload unset means the whole body is your payload, which is why the
identifier_mappings paths above (id, email, …) resolve against the root.
settings is merged, not replaced. Sending only type_matchers will not
drop your request_mapping, and the other way round.
4. Send an event
Post your payload to the provider's webhook_url, signed with its
webhook_secret. See the
Custom Integration quickstart for the signing
details.
Renaming an event type later
Renaming an event type also updates its linked campaigns and matching rules.
Changing a payload schema
schema_version increments whenever payload_schema changes, and it guards against
concurrent edits. Pass the version you read:
{ "payload_schema": { "...": "..." }, "schema_version": 3 }If the version has changed, the request returns 409. Read the definition again,
apply your change to the latest version and retry.