Sources API
Sources are endpoints that receive incoming webhooks.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/sources | List sources |
| POST | /api/sources | Create source |
| GET | /api/sources/{id} | Get source |
| PATCH | /api/sources/{id} | Update source |
| DELETE | /api/sources/{id} | Delete source |
| POST | /api/sources/{id}/rotate-secret | Rotate a Hookbase-generated signing secret |
| GET | /api/sources/{id}/reveal-secret | Reveal the full signing secret |
| GET | /api/sources/{id}/verify-token | Reveal the Meta verify token (WhatsApp) |
| POST | /api/sources/{id}/rotate-verify-token | Generate a new Meta verify token (WhatsApp) |
| GET | /api/sources/{id}/pending-verification | Read a verification token the vendor delivered (Notion) |
| POST | /api/sources/{id}/pending-verification/adopt | Make the pending token the signing secret |
| GET | /api/sources/export | Export sources as JSON |
| POST | /api/sources/import | Import sources from JSON |
| DELETE | /api/sources/bulk | Bulk delete sources |
Every {id} above also accepts the source's slug. The same routes are mounted under
/api/organizations/{orgId}/sources/... for JWT-authenticated callers.
Elsewhere in the API, the sourceId query filter on event list/export, the real-time stream and
recent-events endpoints, the dead letter queue list and redaction policies also takes a slug. A
slug that matches no source returns 404 rather than an empty list.
Source Object
{
"id": "11111111-1111-4111-8111-111111111111",
"organizationId": "eeeeeeee-eeee-4eee-8eee-eeeeeeee0001",
"name": "GitHub Webhooks",
"slug": "github",
"provider": "github",
"description": "Production GitHub webhooks",
"hasSigningSecret": true,
"signingSecretLast4": "...a1b2",
"awaitingSigningSecret": false,
"verifiesWithoutSecret": false,
"rejectInvalidSignatures": true,
"rateLimitPerMinute": 1000,
"isActive": true,
"customDomainId": null,
"ipFilterMode": "allowlist",
"ipAllowlist": ["192.168.1.0/24", "10.0.0.1"],
"ipDenylist": [],
"encryptFields": ["$.payment.card_number"],
"maskFields": ["$.user.email"],
"dedupEnabled": true,
"dedupStrategy": "provider_id",
"dedupWindowHours": 24,
"dedupCustomHeader": null,
"transientMode": false,
"allowedMethods": ["POST"],
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z",
"eventCount": 1523,
"routeCount": 3,
"ingestUrl": "https://api.hookbase.app/ingest/myorg/github"
}Info
The signing secret is not in this object. Responses carry hasSigningSecret and the last four
characters of the secret. The full value is returned exactly twice: once in the response to
POST /api/sources, and from GET /api/sources/{id}/reveal-secret.
ingestUrl is included by Get Source and Create Source. It is not part of the list
response — build it yourself from the org and source slugs if you need it there.
Secret status fields
| Field | Type | Description |
|---|---|---|
| hasSigningSecret | boolean | A signing secret is stored on the source |
| signingSecretLast4 | string | null | Last four characters of the stored secret, for recognising it |
| awaitingSigningSecret | boolean | true when only the vendor can issue this provider's secret (secretSource provider, e.g. stripe, shopify; or asana/notion, which issue it after the ingest URL is registered) and none has been set yet. Events are accepted but stored unverified until it is |
| verifiesWithoutSecret | boolean | true when the provider is verified with a key Hookbase already has (wise, wise-sandbox, aws-sns), so no secret is stored or needed. Read it as "verified", not as "missing secret" |
List Sources
GET /api/sourcesQuery Parameters
| Parameter | Type | Description |
|---|---|---|
| page | number | Page number (default: 1) |
| pageSize | number | Items per page (default: 20, max: 100) |
| enabled | boolean | Filter by enabled status |
| search | string | Search by name or slug |
Example
curl https://api.hookbase.app/api/sources \
-H "Authorization: Bearer whr_your_api_key"Response
{
"sources": [
{
"id": "11111111-1111-4111-8111-111111111111",
"organizationId": "eeeeeeee-eeee-4eee-8eee-eeeeeeee0001",
"name": "GitHub Webhooks",
"slug": "github",
"provider": "github",
"description": "Production GitHub webhooks",
"hasSigningSecret": true,
"signingSecretLast4": "...a1b2",
"awaitingSigningSecret": false,
"verifiesWithoutSecret": false,
"rejectInvalidSignatures": true,
"rateLimitPerMinute": null,
"isActive": true,
"customDomainId": null,
"ipFilterMode": "none",
"ipAllowlist": [],
"ipDenylist": [],
"encryptFields": [],
"maskFields": [],
"dedupEnabled": false,
"dedupStrategy": "auto",
"dedupWindowHours": 24,
"dedupCustomHeader": null,
"transientMode": false,
"allowedMethods": [],
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z",
"eventCount": 1523,
"routeCount": 3
}
],
"pagination": {
"total": 5,
"page": 1,
"pageSize": 20
}
}The array is under sources, not data. Every list endpoint in this API names its array after
the resource.
Create Source
POST /api/sourcesRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Display name |
| slug | string | Yes | URL-safe identifier |
| description | string | No | Optional description |
| provider | string | No | Provider id that selects the signature scheme (see Providers). Omit it and the source verifies as custom |
| signingSecret | string | No | The secret or public key the signature is checked against. Whether you must send it, may omit it, or must not send it depends on the provider — see Signing secrets by provider |
| verifyToken | string | No | Meta providers (whatsapp) only: the Verify token Meta checks when you register the callback URL. 8-256 visible ASCII characters. Omit it to have one generated. Any other provider returns 400 |
| rejectInvalidSignatures | boolean | No | Reject events with invalid signatures (default: false) |
| rateLimitPerMinute | number | No | Max events per minute (null = unlimited) |
| ipFilterMode | string | No | IP filtering mode: none, allowlist, denylist, both (default: none) |
| ipAllowlist | string[] | No | Allowed IP addresses/CIDRs (when mode is allowlist) |
| ipDenylist | string[] | No | Denied IP addresses/CIDRs (when mode is denylist) |
| encryptFields | string[] | No | JSONPath expressions for fields to encrypt at rest |
| maskFields | string[] | No | JSONPath expressions for fields to mask in logs |
| dedupEnabled | boolean | No | Enable deduplication (default: false) |
| dedupStrategy | string | No | Dedup strategy (default: auto). See Deduplication |
| dedupWindowHours | number | No | Dedup window in hours (1-168, default: 24) |
| dedupCustomHeader | string | No | Custom header for idempotency key strategy |
| allowedMethods | string[] | No | HTTP verbs the ingest endpoint accepts: GET, POST, PUT, PATCH, DELETE, HEAD. Omit or pass [] to accept any method. See Accepted HTTP Methods |
The body is validated strictly: an unknown field name is a 400, not silently ignored.
Providers
provider accepts any provider id Hookbase has a signature scheme for — Stripe, GitHub, Shopify,
Slack, Twilio and several dozen more, plus custom (hex HMAC-SHA256 you configure yourself) and
generic (an alias of custom). An unknown value is rejected with a 400 that says so.
The list grows regularly, so it is not repeated here. Browse it on the
integrations page, or read it from the public
Provider Catalog API. A catalog entry's hookbaseProvider is
the value to send as provider — it is not always the same as the catalog id.
Signing secrets by provider
Who produces the secret differs by provider. The catalog reports it per provider as
signatureVerification.secretSource:
secretSource | What to send as signingSecret | If you omit it |
|---|---|---|
provider | The secret the vendor issued, copied from its dashboard | Standard Webhooks providers (standard-webhooks, svix, clerk, resend, render, etsy, stytch), airtable, gitlab-signing-token and supabase-auth-hooks return 400, and their values are format-checked. For the others the source is created with signingSecret: null and awaitingSigningSecret: true (events are accepted unverified) — PATCH in the vendor's value to start verifying. rotate-secret returns 400 for all of them |
operator | A value you choose, or nothing | Hookbase generates one and returns it once in the create response. Paste it into the vendor's webhook settings |
public_key | The vendor's public key (PEM or base64), e.g. Discord or SendGrid | 400 — a public key can't be generated |
built_in | Nothing. Sending a secret is a 400 | The source is created with signingSecret: null and verifiesWithoutSecret: true; Hookbase verifies with the vendor's published key or certificate (wise, wise-sandbox, aws-sns) |
none | Nothing required. The vendor doesn't sign, or Hookbase can't check its scheme; you may still set a secret for custom HMAC | A secret is generated for the custom scheme |
asana and notion issue their secret only once the ingest URL is registered with them. Create
the source without one: the response has signingSecret: null and awaitingSigningSecret: true.
Asana's secret arrives in its registration handshake; Notion's verification token is held for you
— read it with Get Pending Verification and confirm it with
Adopt Pending Verification.
Deduplication Strategies
| Strategy | Description |
|---|---|
auto | Automatically detect provider-specific event IDs |
provider_id | Use provider event ID headers (e.g., X-GitHub-Delivery) |
payload_hash | SHA-256 hash of the payload body |
idempotency_key | Use a custom header specified in dedupCustomHeader |
none | No deduplication |
Signature Verification Fields
Verification is configured with two fields on the source itself — provider and signingSecret.
There is no nested configuration object.
GitHub
{
"provider": "github",
"signingSecret": "your-webhook-secret"
}Stripe
{
"provider": "stripe",
"signingSecret": "whsec_..."
}Slack
{
"provider": "slack",
"signingSecret": "your-signing-secret"
}Generic HMAC
{
"provider": "custom",
"signingSecret": "your-secret"
}No verification
Omit both fields. A source created without a provider falls back to Hookbase's custom scheme
and gets a Hookbase-generated secret. Unless the sender signs with that secret, "no verification"
in practice means every event is stored with signatureValid: false and delivered anyway —
rejectInvalidSignatures defaults to false. See FAQ for what that flag does.
Example
curl -X POST https://api.hookbase.app/api/sources \
-H "Authorization: Bearer whr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "GitHub Production",
"slug": "github-prod",
"description": "Production GitHub webhooks",
"provider": "github",
"signingSecret": "my-secret-key"
}'Response
{
"source": {
"id": "11111111-1111-4111-8111-111111110002",
"organizationId": "eeeeeeee-eeee-4eee-8eee-eeeeeeee0001",
"name": "GitHub Production",
"slug": "github-prod",
"provider": "github",
"description": "Production GitHub webhooks",
"hasSigningSecret": true,
"signingSecretLast4": "...t-key",
"awaitingSigningSecret": false,
"verifiesWithoutSecret": false,
"rejectInvalidSignatures": false,
"rateLimitPerMinute": null,
"isActive": true,
"customDomainId": null,
"ipFilterMode": "none",
"ipAllowlist": [],
"ipDenylist": [],
"encryptFields": [],
"maskFields": [],
"dedupEnabled": false,
"dedupStrategy": "auto",
"dedupWindowHours": 24,
"dedupCustomHeader": null,
"transientMode": false,
"allowedMethods": [],
"createdAt": "2024-01-15T09:00:00Z",
"updatedAt": "2024-01-15T09:00:00Z",
"signingSecret": "my-secret-key",
"eventCount": 0,
"routeCount": 0,
"ingestUrl": "https://api.hookbase.app/ingest/myorg/github-prod"
}
}Warning
This is the only response that contains signingSecret in full. If the provider takes an
operator-chosen secret and you did not supply one, the API generated it, and this is the moment to
store it — afterwards only GET /api/sources/{id}/reveal-secret will give it back.
signingSecret is null in the create response for built_in providers (nothing is stored) and
for vendor-issued secrets you did not supply, such as stripe or asana/notion (the vendor has not
issued it yet, or you have not pasted it; awaitingSigningSecret is true).
For whatsapp, the response also carries verifyToken — the value to type into Meta's
Verify token field. It is returned in full only here; read it later with
Get Verify Token.
Get Source
GET /api/sources/{id}Example
curl https://api.hookbase.app/api/sources/11111111-1111-4111-8111-111111111111 \
-H "Authorization: Bearer whr_your_api_key"Response
{
"source": {
"id": "11111111-1111-4111-8111-111111111111",
"organizationId": "eeeeeeee-eeee-4eee-8eee-eeeeeeee0001",
"name": "GitHub Webhooks",
"slug": "github",
"provider": "github",
"description": "Production GitHub webhooks",
"hasSigningSecret": true,
"signingSecretLast4": "...a1b2",
"awaitingSigningSecret": false,
"verifiesWithoutSecret": false,
"rejectInvalidSignatures": true,
"rateLimitPerMinute": 1000,
"isActive": true,
"customDomainId": null,
"ipFilterMode": "none",
"ipAllowlist": [],
"ipDenylist": [],
"encryptFields": [],
"maskFields": [],
"dedupEnabled": false,
"dedupStrategy": "auto",
"dedupWindowHours": 24,
"dedupCustomHeader": null,
"transientMode": false,
"allowedMethods": [],
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z",
"eventCount": 1523,
"routeCount": 3,
"ingestUrl": "https://api.hookbase.app/ingest/myorg/github"
}
}Update Source
PATCH /api/sources/{id}Request Body
All fields are optional. Only provided fields are updated.
| Field | Type | Description |
|---|---|---|
| name | string | Display name |
| description | string | Optional description |
| provider | string | null | Provider id, or null to fall back to custom |
| signingSecret | string | null | Secret or public key the signature is checked against. null or "" clears it. Format rules are the same as on create, checked against the provider the source will have after the update |
| verifyToken | string | null | Meta providers (whatsapp) only. A value sets it; null or "" generates a new one. Any other provider returns 400 |
| isActive | boolean | Active status |
| rejectInvalidSignatures | boolean | Reject events with invalid signatures |
| rateLimitPerMinute | number | null | Max events per minute (null = unlimited) |
| ipFilterMode | string | none, allowlist, denylist or both |
| ipAllowlist / ipDenylist | string[] | null | IP addresses/CIDRs |
| encryptFields / maskFields | string[] | null | JSONPath expressions |
| dedupEnabled | boolean | Enable deduplication |
| dedupStrategy | string | null | auto, provider_id, payload_hash, idempotency_key or none |
| dedupWindowHours | number | null | Dedup window in hours (1-168) |
| dedupCustomHeader | string | null | Header for the idempotency_key strategy |
| transientMode | boolean | Never store payloads at rest |
| allowedMethods | string[] | HTTP verbs the ingest endpoint accepts. Pass [] to accept any method again |
Switching provider to one whose secret the vendor issues (for example a whsec_ provider) needs
the new signingSecret in the same request, or it is a 400. Switching to asana/notion or to a
built_in provider clears the old secret. Switching to whatsapp generates a verify token if the
source has none.
Warning
The slug cannot be changed after creation as it's part of the webhook URL.
Example
curl -X PATCH https://api.hookbase.app/api/sources/11111111-1111-4111-8111-111111111111 \
-H "Authorization: Bearer whr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "GitHub Production (Updated)",
"isActive": false
}'Response
{
"success": true
}PATCH acknowledges the write and returns nothing else. Read the source back with
GET /api/sources/{id} if you need the updated object.
Delete Source
DELETE /api/sources/{id}Danger
Deleting a source also deletes all associated events and deliveries.
Example
curl -X DELETE https://api.hookbase.app/api/sources/11111111-1111-4111-8111-111111111111 \
-H "Authorization: Bearer whr_your_api_key"Response
{
"success": true
}The status is 200, not 204.
Rotate Secret
Replace a Hookbase-generated signing secret with a new one. The old secret is immediately invalidated.
POST /api/sources/{id}/rotate-secretRotation is for secrets Hookbase generates — providers whose catalog secretSource is operator,
and custom sources — where you paste the new value into the vendor afterwards. For a provider
whose vendor issues the secret (secretSource: provider, such as Stripe), rotating would store a
value the vendor never signs with: regenerate it at the vendor and PATCH it instead.
Where Hookbase can tell that no generated value could ever verify, the request is refused with
400:
| Provider type | Why it's a 400 | What to do instead |
|---|---|---|
Built-in key (wise, wise-sandbox, aws-sns) | The source has no secret | Nothing — it verifies without one |
Public key (discord, sendgrid, …) | Hookbase can't generate a key pair the vendor uses | PATCH the vendor's replacement public key as signingSecret |
Vendor-issued (whsec_ providers, airtable, gitlab-signing-token, …) | Only the vendor can issue it | Regenerate it at the vendor, then PATCH it as signingSecret |
Issued after registration (asana, notion) | Same | Re-register at the vendor, then PATCH it |
Example
curl -X POST https://api.hookbase.app/api/sources/11111111-1111-4111-8111-111111111111/rotate-secret \
-H "Authorization: Bearer whr_your_api_key"Response
{
"signingSecret": "new-generated-secret-value"
}Warning
The new secret is only shown once in the response. Update your webhook provider with the new secret immediately.
{
"error": "wise signs with a public key it publishes, so this source has no secret to rotate."
}Reveal Secret
Return the full signing secret stored on a source. Requires a write-scoped API key (or a member,
admin or owner session): exposing a credential is treated as a write.
GET /api/sources/{id}/reveal-secretExample
curl https://api.hookbase.app/api/sources/github-prod/reveal-secret \
-H "Authorization: Bearer whr_your_api_key"Response
{
"signingSecret": "my-secret-key"
}Returns 404 when the source doesn't exist or has no secret stored (for example a built_in
provider, or asana/notion before the vendor has issued one).
Get Verify Token
Return the Meta Verify token of a WhatsApp source — the value Meta's "Verify and save" checks
when you register the callback URL. It is a separate credential from the App Secret stored in
signingSecret. Same permissions as Reveal Secret.
GET /api/sources/{id}/verify-tokenExample
curl https://api.hookbase.app/api/sources/whatsapp-prod/verify-token \
-H "Authorization: Bearer whr_your_api_key"Response
{
"verifyToken": "3f9c2a7e5b1d4c8a9e0f6b2d7a1c5e3f"
}| Status | When |
|---|---|
400 | The provider has no verify token (anything other than whatsapp) |
404 | Source not found |
Rotate Verify Token
Generate a new verify token for a WhatsApp source. The old one stops working at once, so type the new value into Meta before you next click Verify and save. Existing event delivery is not affected — events are signed with the App Secret, not the verify token.
POST /api/sources/{id}/rotate-verify-tokenExample
curl -X POST https://api.hookbase.app/api/sources/whatsapp-prod/rotate-verify-token \
-H "Authorization: Bearer whr_your_api_key"Response
{
"verifyToken": "9a1e4c7b2f5d8e0a3c6b9f2e5d8a1c4b"
}400 for providers without a verify token, 404 if the source doesn't exist. To set a value of
your own instead, send verifyToken in a PATCH.
Get Pending Verification
When you register the ingest URL with Notion, Notion posts a one-off verification_token to it.
That token is also the secret Notion signs every later event with. Because the request carrying it
is unsigned, Hookbase never adopts it automatically: it holds it (encrypted, for 24 hours) until you
confirm it. Same permissions as Reveal Secret.
GET /api/sources/{id}/pending-verificationExample
curl https://api.hookbase.app/api/sources/notion-prod/pending-verification \
-H "Authorization: Bearer whr_your_api_key"Response
{
"provider": "notion",
"token": "secret_tS2xR8vQ...",
"receivedAt": "2026-10-11T14:02:11.000Z",
"clientIp": "203.0.113.24"
}Paste token into Notion's Verify form. A planted token simply fails there.
Returns 404 with "No verification token is waiting for this source" when nothing is held (none
received yet, it expired, or it was already adopted).
Adopt Pending Verification
Make the held token the source's signing secret. Do this after Notion shows the subscription as verified. The pending entry is deleted once adopted.
POST /api/sources/{id}/pending-verification/adoptExample
curl -X POST https://api.hookbase.app/api/sources/notion-prod/pending-verification/adopt \
-H "Authorization: Bearer whr_your_api_key"Response
{
"success": true
}404 when the source doesn't exist or no token is waiting.
Export Sources
Export sources as a JSON file for backup or migration to another organization.
GET /api/sources/exportQuery Parameters
| Parameter | Type | Description |
|---|---|---|
| ids | string | Comma-separated source IDs to export (optional, exports all if not specified) |
| includeSensitive | boolean | Include signing secrets in export (default: false) |
Example
# Export all sources (secrets redacted)
curl https://api.hookbase.app/api/sources/export \
-H "Authorization: Bearer whr_your_api_key"
# Export specific sources with secrets
curl "https://api.hookbase.app/api/sources/export?ids=11111111-1111-4111-8111-111111110001,11111111-1111-4111-8111-111111110006&includeSensitive=true" \
-H "Authorization: Bearer whr_your_api_key"Response
{
"version": "1.0",
"exportedAt": "2024-01-15T10:30:00Z",
"organizationSlug": "myorg",
"sources": [
{
"name": "GitHub Webhooks",
"slug": "github",
"provider": "github",
"description": "Production GitHub webhooks",
"signingSecret": "***REDACTED***",
"rejectInvalidSignatures": true,
"rateLimitPerMinute": null,
"ipFilterMode": "none",
"ipAllowlist": [],
"ipDenylist": [],
"encryptFields": [],
"maskFields": [],
"dedupEnabled": false,
"dedupStrategy": "auto",
"dedupWindowHours": 24,
"dedupCustomHeader": null,
"transientMode": false,
"allowedMethods": [],
"isActive": true
}
]
}Tip
When includeSensitive is false (default), signing secrets are replaced with ***REDACTED***. A new secret will be generated when importing.
Import Sources
Import sources from a JSON export file.
POST /api/sources/importRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| sources | array | Yes | Array of source objects to import |
| conflictStrategy | string | Yes | How to handle slug conflicts: skip, rename, or overwrite |
| validateOnly | boolean | No | If true, validates without importing (default: false) |
Conflict Strategies
| Strategy | Description |
|---|---|
skip | Skip sources that already exist (by slug) |
rename | Auto-rename conflicting sources (e.g., github → github-1) |
overwrite | Update existing sources with imported data |
Example
curl -X POST https://api.hookbase.app/api/sources/import \
-H "Authorization: Bearer whr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"sources": [
{
"name": "Stripe Payments",
"slug": "stripe",
"provider": "stripe",
"rejectInvalidSignatures": true,
"isActive": true
}
],
"conflictStrategy": "skip"
}'Validation Response
When validateOnly: true:
{
"valid": true,
"validationResults": [
{
"index": 0,
"name": "Stripe Payments",
"slug": "stripe",
"status": "valid",
"errors": [],
"warnings": ["Signing secret is redacted - a new secret will be generated on import"]
}
],
"summary": {
"total": 1,
"toCreate": 1,
"toOverwrite": 0,
"toSkip": 0,
"errors": 0
}
}Import Response
{
"success": true,
"summary": {
"imported": 3,
"skipped": 1,
"overwritten": 0,
"failed": 0
},
"details": {
"imported": ["Stripe Payments", "GitHub Webhooks", "Slack Events"],
"skipped": ["Internal API"],
"overwritten": [],
"failed": []
}
}Bulk Delete Sources
Delete multiple sources in a single request.
DELETE /api/sources/bulkRequest Body
{
"ids": ["11111111-1111-4111-8111-111111111111", "11111111-1111-4111-8111-111111110002", "11111111-1111-4111-8111-111111110009"]
}Example
curl -X DELETE https://api.hookbase.app/api/sources/bulk \
-H "Authorization: Bearer whr_your_api_key" \
-H "Content-Type: application/json" \
-d '{"ids": ["11111111-1111-4111-8111-111111111111", "11111111-1111-4111-8111-111111110002"]}'Response
{
"success": true,
"deleted": 2
}Danger
Deleting sources also deletes all associated events and deliveries. This action cannot be undone.
Error Responses
400 Bad Request
Invalid input data:
{
"error": "Bad Request",
"message": "Slug must be lowercase alphanumeric with hyphens",
"code": "INVALID_SLUG"
}404 Not Found
Source not found:
{
"error": "Not Found",
"message": "Source with ID 11111111-1111-4111-8111-111111110005 not found",
"code": "RESOURCE_NOT_FOUND"
}409 Conflict
Duplicate slug:
{
"error": "Conflict",
"message": "A source with slug 'github' already exists",
"code": "DUPLICATE_SLUG"
}