mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-29 03:09:24 -06:00
Add Webhooks (#364)
This commit is contained in:
@@ -56,7 +56,7 @@ export function APILayout({ method, url, description, headers, bodies, responses
|
||||
{method}
|
||||
</div>
|
||||
<div className="inline text-sm text-slate-500 ">
|
||||
http://localhost:300
|
||||
https://app.formbricks.com
|
||||
<span className="font-bold text-black dark:text-slate-300">{url}</span>
|
||||
</div>
|
||||
<div className="ml-8 mt-4 font-bold dark:text-slate-400">{description}</div>
|
||||
@@ -75,30 +75,34 @@ export function APILayout({ method, url, description, headers, bodies, responses
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 text-base">
|
||||
<p className="not-prose -mb-1 pt-2 font-bold">Body</p>
|
||||
<div>
|
||||
{}
|
||||
{bodies.map((b) => (
|
||||
<Parameter
|
||||
key={b.label}
|
||||
label={b.label}
|
||||
type={b.type}
|
||||
description={b.description}
|
||||
required={b.required}
|
||||
/>
|
||||
))}
|
||||
{example && (
|
||||
<div>
|
||||
<p className="not-prose mb-2 pt-2 font-bold">Body Example</p>
|
||||
{bodies && (
|
||||
<div className="mt-4 text-base">
|
||||
<p className="not-prose -mb-1 pt-2 font-bold">Body</p>
|
||||
<div>
|
||||
{}
|
||||
{bodies?.map((b) => (
|
||||
<Parameter
|
||||
key={b.label}
|
||||
label={b.label}
|
||||
type={b.type}
|
||||
description={b.description}
|
||||
required={b.required}
|
||||
/>
|
||||
))}
|
||||
{example && (
|
||||
<div>
|
||||
<pre>
|
||||
<code>{example}</code>
|
||||
</pre>
|
||||
<p className="not-prose mb-2 pt-2 font-bold">Body Example</p>
|
||||
<div>
|
||||
<pre>
|
||||
<code>{example}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="mt-4 text-base">
|
||||
<p className="not-prose -mb-1 pt-2 font-bold">Responses</p>
|
||||
<div>
|
||||
@@ -194,7 +198,7 @@ function Response({ color, statusCode, description, example }: RespProps) {
|
||||
</div>
|
||||
</div>
|
||||
{example && toggleExample && (
|
||||
<div className="col-span-2 my-3 rounded-lg bg-slate-300 p-2 font-mono dark:bg-slate-600 dark:text-slate-300">
|
||||
<div className="col-span-2 my-3 whitespace-pre-wrap rounded-lg bg-slate-300 p-2 font-mono dark:bg-slate-600 dark:text-slate-300">
|
||||
{example}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -53,8 +53,19 @@ const navigation = [
|
||||
{
|
||||
title: "Client API",
|
||||
links: [
|
||||
{ title: "Create Response", href: "/docs/api/create-response" },
|
||||
{ title: "Update Response", href: "/docs/api/update-response" },
|
||||
{ title: "Overview", href: "/docs/client-api/overview" },
|
||||
{ title: "Create Response", href: "/docs/client-api/create-response" },
|
||||
{ title: "Update Response", href: "/docs/client-api/update-response" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Webhook API",
|
||||
links: [
|
||||
{ title: "Overview", href: "/docs/webhook-api/overview" },
|
||||
{ title: "List Webhooks", href: "/docs/webhook-api/list-webhooks" },
|
||||
{ title: "Get Webhook", href: "/docs/webhook-api/get-webhook" },
|
||||
{ title: "Create Webhook", href: "/docs/webhook-api/create-webhook" },
|
||||
{ title: "Delete Webhook", href: "/docs/webhook-api/delete-webhook" },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: Create response",
|
||||
description: "Learn how to create a new response to a survey via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="POST"
|
||||
url="/api/v1/client/environments/{environmentId}/responses"
|
||||
description="Add a new submission to a form by form ID."
|
||||
headers={[]}
|
||||
bodies={[
|
||||
{
|
||||
label: "surveyId",
|
||||
type: "string",
|
||||
description: "The customer and metadata you want to link the submission to.",
|
||||
},
|
||||
{
|
||||
label: "personId",
|
||||
type: "string",
|
||||
description: "Customer or user email. This is the primary key to identify users",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "response",
|
||||
type: "JSON",
|
||||
description: "The content of the submission.",
|
||||
},
|
||||
{
|
||||
label: "response.data",
|
||||
type: "string",
|
||||
description: "The data of the response as JSON object.",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "response.finished",
|
||||
type: "boolean",
|
||||
description: "Determines if submission is marked as complete.",
|
||||
},
|
||||
]}
|
||||
example={`{
|
||||
"response": {
|
||||
data: {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
},
|
||||
finished: true, // optional
|
||||
},
|
||||
"personId: "clfqjny0v000ayzgsycx54a2c",
|
||||
"surveyId": "clfqz1esd0000yzah51trddn8"
|
||||
}`}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "success",
|
||||
example: "{ // Response Object as JSON }",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| response | yes | - | The response object (answers to the survey). It requires a `data` object. In this object the key is the questionId, the value the answer of the user to this question. |
|
||||
| personId | yes | - | The person this response is connected to. |
|
||||
| surveyId | yes | - | The survey this response is connected to. |
|
||||
| finished | no | false | Mark a response as complete to be able to filter accordingly. |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,75 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: Update submission",
|
||||
description: "Learn how to update a new response to a survey via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="POST"
|
||||
url="/api/v1/client/environments/{environmentId}/responses/{responseId}"
|
||||
description="Update an existing response in a survey."
|
||||
headers={[]}
|
||||
bodies={[
|
||||
{
|
||||
label: "customer",
|
||||
type: "JSON",
|
||||
description: "The customer and metadata you want to link the submission to.",
|
||||
},
|
||||
{
|
||||
label: "customer.email",
|
||||
type: "email",
|
||||
description: "Customer or user email. This is the primary key to identify users",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "customer.prop",
|
||||
type: "string",
|
||||
description:
|
||||
"Pass value to create user property. You can filter / create cohorts for future surveys based on props.",
|
||||
},
|
||||
{
|
||||
label: "data",
|
||||
type: "JSON",
|
||||
description: "The content of the submission.",
|
||||
},
|
||||
{
|
||||
label: "data.fieldName",
|
||||
type: "string",
|
||||
description: "Add value to input field by name.",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "finished",
|
||||
type: "boolean",
|
||||
description: "Determines if submission is marked as complete.",
|
||||
},
|
||||
]}
|
||||
example={`{
|
||||
"response": {
|
||||
data: {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
},
|
||||
finished: true, // optional
|
||||
},
|
||||
"personId: "clfqjny0v000ayzgsycx54a2c",
|
||||
"surveyId": "clfqz1esd0000yzah51trddn8"
|
||||
}`}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "success",
|
||||
example: "{ // Response }",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| response | yes | - | The response object (answers to the survey). It requires a `data` object. In this object the key is the questionId, the value the answer of the user to this question. |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: Create response",
|
||||
description: "Learn how to create a new response to a survey via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="POST"
|
||||
url="/api/v1/client/responses"
|
||||
description="Add a new response to a survey."
|
||||
headers={[]}
|
||||
bodies={[
|
||||
{
|
||||
label: "surveyId",
|
||||
type: "string",
|
||||
description: "The id of the survey the response belongs to.",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "personId",
|
||||
type: "string",
|
||||
description: "Internal Formbricks id to identify the user sending the response (optional)",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
label: "finished",
|
||||
type: "boolean",
|
||||
description: "Marks whether the response is complete or not.",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "data",
|
||||
type: "string",
|
||||
description: "The data of the response as JSON object (key: questionId, value: answer).",
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
example={`{
|
||||
"personId: "clfqjny0v000ayzgsycx54a2c",
|
||||
"surveyId": "clfqz1esd0000yzah51trddn8",
|
||||
"finished": true,
|
||||
"data": {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
}
|
||||
}`}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "success. Returns a response object as JSON.",
|
||||
example: `{
|
||||
"data": {
|
||||
"id": "clisyqeoi000219t52m5gopke",
|
||||
"surveyId": "clfqz1esd0000yzah51trddn8",
|
||||
"finished": true,
|
||||
"person": {
|
||||
id: "clfqjny0v000ayzgsycx54a2c",
|
||||
attributes: {
|
||||
"email": "me@johndoe.com"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "400",
|
||||
description: "error. bad request",
|
||||
example: `{
|
||||
"code": "bad_request",
|
||||
"message": "surveyId was not provided.",
|
||||
"details": {
|
||||
"surveyId": "This field is required."
|
||||
}
|
||||
}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| data | yes | - | The response data object (answers to the survey). In this object the key is the questionId, the value the answer of the user to this question. |
|
||||
| personId | no | - | The person this response is connected to. |
|
||||
| surveyId | yes | - | The survey this response is connected to. |
|
||||
| finished | yes | false | Mark a response as complete to be able to filter accordingly. |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
12
apps/formbricks-com/pages/docs/client-api/overview/index.mdx
Normal file
12
apps/formbricks-com/pages/docs/client-api/overview/index.mdx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const meta = {
|
||||
title: "Client API Overview",
|
||||
description:
|
||||
"Explore the Formbricks Public Client API for client-side tasks and integration into your website.",
|
||||
};
|
||||
|
||||
The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: Update submission",
|
||||
description: "Learn how to update a new response to a survey via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="POST"
|
||||
url="/api/v1/client/responses/[responseId]"
|
||||
description="Update an existing response in a survey."
|
||||
headers={[]}
|
||||
bodies={[
|
||||
{
|
||||
label: "data",
|
||||
type: "string",
|
||||
description: "The data of the response as JSON object (key: questionId, value: answer).",
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
example={`{
|
||||
"personId: "clfqjny0v000ayzgsycx54a2c",
|
||||
"surveyId": "clfqz1esd0000yzah51trddn8",
|
||||
"finished": true,
|
||||
"data": {
|
||||
"clggpvpvu0009n40g8ikawby8": 5,
|
||||
}
|
||||
}`}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "success. Returns a response object as JSON.",
|
||||
example: `{
|
||||
"data": {
|
||||
"id": "clisyqeoi000219t52m5gopke",
|
||||
"surveyId": "clfqz1esd0000yzah51trddn8",
|
||||
"finished": true,
|
||||
"person": {
|
||||
id: "clfqjny0v000ayzgsycx54a2c",
|
||||
attributes: {
|
||||
"email": "me@johndoe.com"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"clfqjny0v0003yzgscnog1j9i": 10,
|
||||
"clfqjtn8n0070yzgs6jgx9rog": "I love Formbricks",
|
||||
"clggpvpvu0009n40g8ikawby8": 5
|
||||
}
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "400",
|
||||
description: "error. bad request",
|
||||
example: `{
|
||||
"code": "bad_request",
|
||||
"message": "data was not provided.",
|
||||
"details": {
|
||||
"data": "This field is required."
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "404",
|
||||
description: "error. not found",
|
||||
example: `{
|
||||
"code": "not_found",
|
||||
"message": "Response not found"
|
||||
}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| data | yes | - | The response data object (answers to the survey). In this object the key is the questionId, the value the answer of the user to this question. |
|
||||
| finished | yes | false | Mark a response as complete to be able to filter accordingly. |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,90 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: Create webhook",
|
||||
description: "Learn how to create a new webhook via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="POST"
|
||||
url="/api/v1/webhooks"
|
||||
description="Add a new webhook."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
bodies={[
|
||||
{
|
||||
label: "url",
|
||||
type: "string",
|
||||
description: "The URL where the webhook will send data to.",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: "trigger",
|
||||
type: "string",
|
||||
description: "The event that will trigger the webhook.",
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
example={`{
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"trigger": "responseFinished"
|
||||
}`}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "Success. Returns a webhook object as JSON.",
|
||||
example: `{
|
||||
"data": {
|
||||
"id": "cliu1kdza000219zftad4ip6c",
|
||||
"createdAt": "2023-06-13T08:49:04.198Z",
|
||||
"updatedAt": "2023-06-13T08:49:04.198Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": [
|
||||
"responseFinished"
|
||||
]
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "400",
|
||||
description: "Error. Bad request.",
|
||||
example: `{
|
||||
"code": "bad_request",
|
||||
"message": "Missing trigger",
|
||||
"details": {
|
||||
"missing_field": "trigger"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "401",
|
||||
description: "Error. Not authenticated.",
|
||||
example: `{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
| field name | required | default | description |
|
||||
| ---------- | -------- | ------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| url | yes | - | The endpoint that the webhook will send data to |
|
||||
| trigger | yes | - | The event that will trigger the webhook ("responseCreated" or "responseUpdated" or "responseFinished") |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: Delete Webhook",
|
||||
description: "Learn how to delete a specific webhook by its ID via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="DELETE"
|
||||
url="/api/v1/webhooks/[webhookId]"
|
||||
description="Delete a specific webhook by its ID."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "Success. Returns the deleted webhook object as JSON.",
|
||||
example: `{
|
||||
"data": {
|
||||
"id": "cliu167rk000019zfhbo68bar",
|
||||
"createdAt": "2023-06-13T08:38:02.960Z",
|
||||
"updatedAt": "2023-06-13T08:38:02.960Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": [
|
||||
"responseFinished"
|
||||
]
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "401",
|
||||
description: "Error. Not authenticated.",
|
||||
example: `{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "404",
|
||||
description: "Error. Webhook not found.",
|
||||
example: `{
|
||||
"code": "not_found",
|
||||
"message": "Webhook not found.",
|
||||
"details": {
|
||||
"webhookId": "The requested webhook does not exist."
|
||||
}
|
||||
}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: Get Webhook",
|
||||
description: "Learn how to retrieve a specific webhook by its ID via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="GET"
|
||||
url="/api/v1/webhooks/[webhookId]"
|
||||
description="Retrieve a specific webhook by its ID."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "Success. Returns a webhook object as JSON.",
|
||||
example: `{
|
||||
"data": {
|
||||
"id": "cliu167rk000019zfhbo68bar",
|
||||
"createdAt": "2023-06-13T08:38:02.960Z",
|
||||
"updatedAt": "2023-06-13T08:38:02.960Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": [
|
||||
"responseFinished"
|
||||
]
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "401",
|
||||
description: "Error. Not authenticated.",
|
||||
example: `{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { APILayout } from "@/components/shared/APILayout.tsx";
|
||||
|
||||
export const meta = {
|
||||
title: "API: List Webhooks",
|
||||
description: "Learn how to retrieve a list of all webhooks via API.",
|
||||
};
|
||||
|
||||
<APILayout
|
||||
method="GET"
|
||||
url="/api/v1/webhooks"
|
||||
description="Retrieve a list of all webhooks."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
responses={[
|
||||
{
|
||||
color: "green",
|
||||
statusCode: "200",
|
||||
description: "Success. Returns an array of webhook objects as JSON.",
|
||||
example: `{
|
||||
"data": [
|
||||
{
|
||||
"id": "cliu1kdza000219zftad4ip6c",
|
||||
"createdAt": "2023-06-13T08:49:04.198Z",
|
||||
"updatedAt": "2023-06-13T08:49:04.198Z",
|
||||
"url": "https://mysystem.com/myendpoint",
|
||||
"environmentId": "clisypjy4000319t4imm289uo",
|
||||
"triggers": [
|
||||
"responseFinished"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
{
|
||||
color: "brown",
|
||||
statusCode: "401",
|
||||
description: "Error. Not authenticated.",
|
||||
example: `{
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const meta = {
|
||||
title: "Webhook API Overview",
|
||||
description: "Learn how to use the Formbricks Webhook API.",
|
||||
};
|
||||
|
||||
Formbricks' Webhook API offers a powerful interface for interacting with webhooks. Webhooks in Formbricks allow you to receive real-time HTTP notifications of changes to specific objects in the Formbricks environment.
|
||||
|
||||
Our API has several REST endpoints enabling you to manage these webhooks, providing a great deal of flexibility:
|
||||
|
||||
1. **List Webhooks:** Retrieve a list of all existing webhooks.
|
||||
2. **Create a New Webhook:** Add a new webhook to your system.
|
||||
3. **Get a Specific Webhook:** Query the details of a specific webhook using its unique ID.
|
||||
4. **Delete a Webhook:** Remove an existing webhook.
|
||||
|
||||
These APIs are designed to facilitate seamless integration of Formbricks with third-party systems. By making use of our webhook API, you can automate the process of sending data to these systems whenever significant events occur within your Formbricks environment.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,14 +1,12 @@
|
||||
import { headers } from "next/headers";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { NextResponse } from "next/server";
|
||||
import { hashApiKey } from "@/lib/api/apiHelper";
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export async function GET(_: Request, { params }: { params: { webhookId: string } }) {
|
||||
const apiKey = headers().get("x-api-key");
|
||||
if (!apiKey) {
|
||||
return new Response("Not authenticated. This route is only available via API-Key authorization", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
const apiKeyData = await prisma.apiKey.findUnique({
|
||||
where: {
|
||||
@@ -19,9 +17,7 @@ export async function GET(_: Request, { params }: { params: { webhookId: string
|
||||
},
|
||||
});
|
||||
if (!apiKeyData) {
|
||||
return new Response("Not authenticated", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
|
||||
// add webhook to database
|
||||
@@ -31,19 +27,15 @@ export async function GET(_: Request, { params }: { params: { webhookId: string
|
||||
},
|
||||
});
|
||||
if (!webhook) {
|
||||
return new Response("Webhook not found", {
|
||||
status: 404,
|
||||
});
|
||||
return responses.notFoundResponse("Webhook", params.webhookId);
|
||||
}
|
||||
return NextResponse.json({ data: webhook });
|
||||
return responses.successResponse(webhook);
|
||||
}
|
||||
|
||||
export async function DELETE(_: Request, { params }: { params: { webhookId: string } }) {
|
||||
const apiKey = headers().get("x-api-key");
|
||||
if (!apiKey) {
|
||||
return new Response("Not authenticated. This route is only available via API-Key authorization", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
const apiKeyData = await prisma.apiKey.findUnique({
|
||||
where: {
|
||||
@@ -54,9 +46,7 @@ export async function DELETE(_: Request, { params }: { params: { webhookId: stri
|
||||
},
|
||||
});
|
||||
if (!apiKeyData) {
|
||||
return new Response("Not authenticated", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
|
||||
// add webhook to database
|
||||
@@ -66,9 +56,7 @@ export async function DELETE(_: Request, { params }: { params: { webhookId: stri
|
||||
},
|
||||
});
|
||||
if (!webhook) {
|
||||
return new Response("Webhook not found", {
|
||||
status: 404,
|
||||
});
|
||||
return responses.notFoundResponse("Webhook", params.webhookId);
|
||||
}
|
||||
return NextResponse.json({ data: webhook });
|
||||
return responses.successResponse(webhook);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ import { headers } from "next/headers";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { NextResponse } from "next/server";
|
||||
import { hashApiKey } from "@/lib/api/apiHelper";
|
||||
import { responses } from "@/lib/api/response";
|
||||
|
||||
export async function GET() {
|
||||
const apiKey = headers().get("x-api-key");
|
||||
if (!apiKey) {
|
||||
return new Response("Not authenticated. This route is only available via API-Key authorization", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
const apiKeyData = await prisma.apiKey.findUnique({
|
||||
where: {
|
||||
@@ -19,9 +18,7 @@ export async function GET() {
|
||||
},
|
||||
});
|
||||
if (!apiKeyData) {
|
||||
return new Response("Not authenticated", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
|
||||
// add webhook to database
|
||||
@@ -36,9 +33,7 @@ export async function GET() {
|
||||
export async function POST(request: Request) {
|
||||
const apiKey = headers().get("x-api-key");
|
||||
if (!apiKey) {
|
||||
return new Response("Not authenticated. This route is only available via API-Key authorization", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
const apiKeyData = await prisma.apiKey.findUnique({
|
||||
where: {
|
||||
@@ -49,21 +44,15 @@ export async function POST(request: Request) {
|
||||
},
|
||||
});
|
||||
if (!apiKeyData) {
|
||||
return new Response("Not authenticated", {
|
||||
status: 401,
|
||||
});
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
const { url, trigger } = await request.json();
|
||||
if (!url) {
|
||||
return new Response("Missing url", {
|
||||
status: 400,
|
||||
});
|
||||
return responses.missingFieldResponse("url");
|
||||
}
|
||||
|
||||
if (!trigger) {
|
||||
return new Response("Missing trigger", {
|
||||
status: 400,
|
||||
});
|
||||
return responses.missingFieldResponse("trigger");
|
||||
}
|
||||
|
||||
// add webhook to database
|
||||
@@ -78,5 +67,5 @@ export async function POST(request: Request) {
|
||||
},
|
||||
},
|
||||
});
|
||||
return NextResponse.json({ data: webhook });
|
||||
return responses.successResponse(webhook);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,13 @@ export interface ApiSuccessResponse<T = { [key: string]: any }> {
|
||||
}
|
||||
|
||||
export interface ApiErrorResponse {
|
||||
code: "not_found" | "bad_request" | "internal_server_error" | "unauthorized" | "method_not_allowed";
|
||||
code:
|
||||
| "not_found"
|
||||
| "bad_request"
|
||||
| "internal_server_error"
|
||||
| "unauthorized"
|
||||
| "method_not_allowed"
|
||||
| "not_authenticated";
|
||||
message: string;
|
||||
details: {
|
||||
[key: string]: string | string[] | number | number[] | boolean | boolean[];
|
||||
@@ -80,6 +86,21 @@ const notFoundResponse = (resourceType: string, resourceId: string, cors: boolea
|
||||
}
|
||||
);
|
||||
|
||||
const notAuthenticatedResponse = (cors: boolean = false) =>
|
||||
NextResponse.json(
|
||||
{
|
||||
code: "not_authenticated",
|
||||
message: "Not authenticated",
|
||||
details: {
|
||||
"X-Api-Key": "Header not provided or API Key invalid",
|
||||
},
|
||||
} as ApiErrorResponse,
|
||||
{
|
||||
status: 401,
|
||||
...(cors && { headers: corsHeaders }),
|
||||
}
|
||||
);
|
||||
|
||||
const successResponse = (data: Object, cors: boolean = false) =>
|
||||
NextResponse.json(
|
||||
{
|
||||
@@ -95,6 +116,7 @@ export const responses = {
|
||||
badRequestResponse,
|
||||
missingFieldResponse,
|
||||
methodNotAllowedResponse,
|
||||
notAuthenticatedResponse,
|
||||
notFoundResponse,
|
||||
successResponse,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user