Overview
Adapt integrates with Slack using OAuth 2.0 to send direct message notifications when crawl jobs complete or fail. Connect your Slack workspace and link your user account to start receiving updates.
Key Features:
OAuth 2.0 workspace connection
Direct message notifications per user
Automatic user linking via email matching
Configurable notification preferences
Organisation-wide workspace sharing
OAuth Flow
Initiating Connection
Start the Slack OAuth flow:
POST /v1/integrations/slack
Authorization : Bearer <your_jwt_token>
Response:
{
"status" : "success" ,
"data" : {
"auth_url" : "https://slack.com/oauth/v2/authorize?client_id=..."
},
"message" : "Redirect to this URL to connect Slack"
}
Redirect the user to the auth_url to authorize the app.
Required OAuth Scopes
From internal/api/slack.go:61-62, Adapt requests:
chat:write - Send messages to channels
im:write - Send direct messages to users
users:read - List workspace members
users:read.email - Match users by email address
const (
slackOAuthScopes = "chat:write,im:write,users:read,users:read.email"
slackAPITimeout = 30 * time . Second
)
OAuth Callback
Slack redirects to:
https://your-domain.com/v1/integrations/slack/callback?code=xxx&state=xxx
Adapt handles this automatically (internal/api/slack.go:238-313):
Validate State
Verify the HMAC-signed state parameter to prevent CSRF attacks.
Exchange Code
Trade the authorization code for an access token using Slack’s OAuth v2 endpoint.
Store Connection
Save the workspace connection with workspace ID, name, and bot user ID.
Secure Token
Store the bot access token in Supabase Vault (encrypted at rest).
Redirect
Return to settings page with success status and connection ID for auto-linking.
Connection Storage
From internal/api/slack.go:281-296:
now := time . Now (). UTC ()
conn := & db . SlackConnection {
ID : uuid . New (). String (),
OrganisationID : state . OrgID ,
WorkspaceID : resp . Team . ID ,
WorkspaceName : resp . Team . Name ,
BotUserID : resp . BotUserID ,
InstallingUserID : & state . UserID ,
CreatedAt : now ,
UpdatedAt : now ,
}
User Linking
Automatic Linking
When you connect a Slack workspace, Adapt attempts to link your user account automatically:
Email Matching - Looks up your Slack user ID using your email address
Profile Data - Uses slack_user_id from your Supabase profile if available
Manual Override - Allows explicit Slack user ID in the request body
Link Your Account
POST /v1/integrations/slack/{connection_id}/link-user
Authorization : Bearer <your_jwt_token>
Content-Type : application/json
{
"slack_user_id" : "U01234ABCDE" , // Optional - will auto-detect if omitted
"dm_notifications" : true
}
Response:
{
"status" : "success" ,
"data" : {
"id" : "link_xyz789" ,
"slack_user_id" : "U01234ABCDE" ,
"dm_notifications" : true ,
"created_at" : "2024-03-03T12:00:00Z"
},
"message" : "Slack user linked successfully"
}
Email Lookup Logic
From internal/api/slack.go:511-529:
// If still no Slack user ID, try to find by email
if slackUserID == "" && userClaims . Email != "" {
token , err := h . DB . GetSlackToken ( r . Context (), connectionID )
httpClient := & http . Client { Timeout : slackAPITimeout }
client := slack . New ( token , slack . OptionHTTPClient ( httpClient ))
slackUser , err := client . GetUserByEmail ( userClaims . Email )
if err != nil {
BadRequest ( w , r , "Could not find your Slack user. Make sure your email matches your Slack account." )
return
}
slackUserID = slackUser . ID
}
Email matching requires your Slack workspace email to match your Adapt account email.
List Workspace Users
To manually select a user, fetch the workspace member list:
GET /v1/integrations/slack/{connection_id}/users
Authorization : Bearer <your_jwt_token>
Response:
{
"status" : "success" ,
"data" : [
{
"id" : "U01234ABCDE" ,
"name" : "john.doe" ,
"real_name" : "John Doe" ,
"email" : "[email protected] " ,
"display_name" : "John"
}
]
}
Get Your Link Status
GET /v1/integrations/slack/{connection_id}/user-link
Authorization : Bearer <your_jwt_token>
Returns your current link status or 404 if not linked.
Unlink Your Account
DELETE /v1/integrations/slack/{connection_id}/link-user
Authorization : Bearer <your_jwt_token>
Removes your user link. You’ll stop receiving notifications.
Notification Preferences
Update Settings
Toggle DM notifications on or off:
PUT /v1/integrations/slack/{connection_id}/link-user
Authorization : Bearer <your_jwt_token>
Content-Type : application/json
{
"dm_notifications" : false
}
From internal/api/slack.go:592-620, this updates your notification preferences without unlinking.
Setting dm_notifications: false stops all notifications but preserves your user link. Re-enable anytime without re-linking.
Connection Management
List Connections
GET /v1/integrations/slack
Authorization : Bearer <your_jwt_token>
Response:
{
"status" : "success" ,
"data" : [
{
"id" : "conn_abc123" ,
"workspace_id" : "T01234ABCDE" ,
"workspace_name" : "Acme Corp" ,
"created_at" : "2024-03-03T10:00:00Z"
}
]
}
Get Connection Details
Retrieve connection info with your user link status:
GET /v1/integrations/slack/{connection_id}
Authorization : Bearer <your_jwt_token>
Response:
{
"status" : "success" ,
"data" : {
"connection" : {
"id" : "conn_abc123" ,
"workspace_id" : "T01234ABCDE" ,
"workspace_name" : "Acme Corp" ,
"created_at" : "2024-03-03T10:00:00Z"
},
"user_link" : {
"id" : "link_xyz789" ,
"slack_user_id" : "U01234ABCDE" ,
"dm_notifications" : true ,
"created_at" : "2024-03-03T12:00:00Z"
}
}
}
Delete Connection
Disconnect the Slack workspace:
DELETE /v1/integrations/slack/{connection_id}
Authorization : Bearer <your_jwt_token>
This removes:
The workspace connection
All user links for that workspace
The stored bot token from Vault
Deleting a connection affects all users in your organisation. They’ll need to reconnect and re-link their accounts.
When a crawl job completes or fails, Adapt sends a direct message:
Job Completed:
✅ Crawl Complete: example.com
150 pages crawled in 2m 34s
• 145 successful
• 3 not found (404)
• 2 server errors
View results: https://adapt.app.goodnative.co/jobs/job_123abc
Job Failed:
❌ Crawl Failed: example.com
Error: Connection timeout after 30s
Attempts: 3/3
View details: https://adapt.app.goodnative.co/jobs/job_123abc
The notification format is optimised for mobile devices with clear status indicators and direct links.
Security
Token Storage
Bot access tokens are stored in Supabase Vault (encrypted at rest):
if err := h . DB . StoreSlackToken ( r . Context (), conn . ID , resp . AccessToken ); err != nil {
h . redirectToSettingsWithError ( w , r , "Slack" , "Failed to secure connection" , "notifications" , "slack" )
return
}
From internal/api/slack.go:299-303.
State Validation
OAuth state parameters are HMAC-signed using SUPABASE_JWT_SECRET:
state , err := h . generateOAuthState ( userClaims . UserID , orgID )
if err != nil {
InternalError ( w , r , err )
return
}
From internal/api/slack.go:218-223.
API Rate Limits
The Slack API client uses a 30-second timeout for all requests to prevent hanging operations.
Environment Variables
# Required for OAuth
SLACK_CLIENT_ID = your_client_id
SLACK_CLIENT_SECRET = your_client_secret
SLACK_REDIRECT_URI = https://your-domain.com/v1/integrations/slack/callback
# Required for state signing
SUPABASE_JWT_SECRET = your_jwt_secret
# App URL for notification links
APP_URL = https://your-domain.com
Common Issues
Email Match Fails
Symptom: User linking fails with “Could not find your Slack user”
Cause: Email in Slack doesn’t match your Adapt account email
Solution: Manually select your Slack user from the workspace members list
No Notifications Received
Causes:
User not linked - check link status with GET /user-link
DM notifications disabled - check dm_notifications setting
Bot removed from workspace - reconnect the workspace
Solution: Verify link status and notification settings
Multiple Workspaces
You can connect multiple Slack workspaces to a single Adapt organisation. Link your user account in each workspace to receive notifications across all of them.
API Reference
Endpoint Method Description /v1/integrations/slackPOST Initiate OAuth flow /v1/integrations/slackGET List connections /v1/integrations/slack/{id}GET Get connection details /v1/integrations/slack/{id}DELETE Remove connection /v1/integrations/slack/{id}/link-userPOST Link your account /v1/integrations/slack/{id}/link-userPUT Update notifications /v1/integrations/slack/{id}/link-userDELETE Unlink your account /v1/integrations/slack/{id}/user-linkGET Get link status /v1/integrations/slack/{id}/usersGET List workspace members
Next Steps
Webflow Integration Auto-crawl on publish events
Custom Webhooks Build your own integrations