From 91bc558394343c881cbbc54ef5ff3520c5c759e1 Mon Sep 17 00:00:00 2001 From: Steven Eubank Date: Fri, 20 Jun 2025 11:25:06 -0700 Subject: [PATCH 1/3] feat(partners)add-enablement-docs Draft of converting 2 internal docs into public facing partnership enablement pages - account provisioning - oauth --- .../account-provisioning-api.mdx | 215 ++++++++++++ docs/product/partnership-platform/index.mdx | 58 ++++ .../oauth-integration.mdx | 318 ++++++++++++++++++ 3 files changed, 591 insertions(+) create mode 100644 docs/product/partnership-platform/account-provisioning-api.mdx create mode 100644 docs/product/partnership-platform/index.mdx create mode 100644 docs/product/partnership-platform/oauth-integration.mdx diff --git a/docs/product/partnership-platform/account-provisioning-api.mdx b/docs/product/partnership-platform/account-provisioning-api.mdx new file mode 100644 index 0000000000000..f28485cb767bd --- /dev/null +++ b/docs/product/partnership-platform/account-provisioning-api.mdx @@ -0,0 +1,215 @@ +--- +title: "Account Provisioning API" +description: "Learn how to automatically provision Sentry organizations for your customers using our provisioning API." +sidebar_order: 1 +--- + +# Account Provisioning API + +The Sentry Provisioning API allows partner platforms to automatically create Sentry organizations for their customers. This enables seamless onboarding of your users to Sentry's error monitoring and performance insights. + +## Overview + +When you call the Sentry provisioning API on behalf of your customer for the first time, the customer receives: + +- **A Sentry Organization** with the same name as their organization on your platform +- **A Default Team** for collaboration within the organization +- **Organization Ownership** assigned to the provided email address +- **Subscription Plan** based on your partnership agreement +- **Pre-configured Projects** (optional) that you specify +- **Integration Token** (optional) for managing the organization programmatically + +## API Endpoint + +``` +POST https://sentry.io/remote/channel-provision/account/ +``` + +## Authentication + +The API requires a custom `X-Request-Signature` header with a SHA256 HMAC signature. The signature is built using your `API_SECRET_KEY` and the request body. + +### Signature Generation + +```python +import hmac +import hashlib +import json + +def generate_signature(data, secret_key): + secret_key_bytes = secret_key.encode("utf-8") + json_data = json.dumps(data) + data_bytes = json_data.encode("utf-8") + signature = hmac.new( + key=secret_key_bytes, + msg=data_bytes, + digestmod=hashlib.sha256 + ).hexdigest() + return signature +``` + +## Request Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `channel` | string | Yes | Your partner name (case insensitive) | +| `email` | string | Yes | Customer's email address (becomes org owner) | +| `organizationName` | string | Yes | Customer's organization name (max 50 chars) | +| `organizationID` | string | Yes | Unique ID for customer's organization on your platform | +| `hasAgreedTerms` | boolean | Yes | Customer's agreement to Sentry terms | +| `timestamp` | integer | Yes | Current timestamp for request expiration | +| `url` | string | Yes | Must be `https://sentry.io/remote/channel-provision/account/` | +| `projects` | array | No | List of projects to create | +| `region` | string | No | Data residency (`us` or `de`, default: `us`) | +| `isTest` | boolean | No | Set to `true` for testing (default: `false`) | + +### Project Object Structure + +```json +{ + "name": "project-name", + "platform": "java" +} +``` + +### Supported Platforms + +The `platform` field supports all Sentry platform identifiers, including: +- `javascript`, `python`, `java`, `csharp`, `php`, `ruby`, `go`, `rust`, `swift`, `kotlin`, `dart`, and more + +## Example Request + +```python +import requests +import json +import time + +URL = "https://sentry.io/remote/channel-provision/account/" +API_SECRET_KEY = "your-partner-specific-secret-key" + +DATA = { + "channel": "Your Platform Name", + "organizationName": "Customer Corp", + "organizationID": "unique-customer-id", + "email": "customer@example.com", + "projects": [ + {"name": "web-app", "platform": "javascript"}, + {"name": "api-service", "platform": "python"} + ], + "hasAgreedTerms": True, + "timestamp": int(time.time()), + "url": URL, + "isTest": False +} + +# Generate signature +signature = generate_signature(DATA, API_SECRET_KEY) + +# Make request +response = requests.post( + URL, + data=json.dumps(DATA), + headers={"X-Request-Signature": signature} +) + +print(response.json()) +``` + +## Response + +### Success (200) + +```json +{ + "email": "customer@example.com", + "organization": { + "id": "123", + "slug": "customer-corp", + "name": "Customer Corp" + }, + "projects": [ + { + "dsn": "https://...@sentry.io/123", + "project": { + "id": "456", + "slug": "web-app", + "name": "web-app", + "platform": "javascript" + } + } + ], + "integration_api_token": "your-integration-token" +} +``` + +### Error Responses + +- **400 Bad Request**: Invalid parameters (check response body for details) +- **401 Unauthorized**: Invalid signature (check your API_SECRET_KEY) +- **500 Server Error**: Internal server error (check response body for details) + +## Additional Operations + +### Adding Projects + +Call the API again with new projects to add them to an existing organization: + +```python +DATA = { + # ... existing parameters ... + "projects": [ + {"name": "new-service", "platform": "go"} + ] +} +``` + +### Adding Managers + +Add additional users as managers to the organization: + +```python +DATA = { + # ... existing parameters ... + "email": "manager@example.com" # New manager email +} +``` + +## Customer Experience + +### Welcome Email + +When you provision an organization, the customer receives: +- A welcome email with organization details +- Instructions for managing their Sentry organization +- Information about your partnership integration +- Support contact information + +### Partner-Specific Features + +Based on your partnership agreement, you can enable: + +- **Partner Presence**: Show your platform as an organization member +- **Persistent Plan**: Allow customers to upgrade plans independently +- **Quota Visibility**: Control visibility of usage quotas + +## Integration Token + +The response includes an `integration_api_token` that allows you to: +- Create and manage projects +- Manage organization members +- Access Sentry APIs on behalf of the customer + +Token permissions are defined in your partnership agreement. + +## Best Practices + +1. **Store organization mappings**: Keep track of the relationship between your customer IDs and Sentry organization IDs +2. **Handle errors gracefully**: Implement proper error handling for failed provisioning +3. **Use test mode**: Set `isTest: true` during development and testing +4. **Respect rate limits**: Implement appropriate delays between requests +5. **Secure your secret key**: Store your API_SECRET_KEY securely and never expose it in client-side code + +## Support + +For questions about the provisioning API or partnership integration, contact: +**Email:** partnership-platform@sentry.io \ No newline at end of file diff --git a/docs/product/partnership-platform/index.mdx b/docs/product/partnership-platform/index.mdx new file mode 100644 index 0000000000000..436f4a28da0a0 --- /dev/null +++ b/docs/product/partnership-platform/index.mdx @@ -0,0 +1,58 @@ +--- +title: "Partnership Platform" +description: "Learn how to integrate Sentry into your platform and provide error monitoring and performance insights to your customers." +sidebar_order: 35 +--- + +# Partnership Platform + +Sentry offers powerful partnership capabilities that allow you to integrate error monitoring and performance insights directly into your platform. Whether you're a developer platform, hosting provider, or SaaS application, you can leverage Sentry's monitoring capabilities to enhance your customer experience. + +## What's Available + +Sentry provides two main integration paths for partners: + +### 1. [Account Provisioning API](/product/partnership-platform/account-provisioning-api/) + +Automatically create Sentry organizations for your customers with our provisioning API. This allows you to: + +- **Seamlessly onboard customers** to Sentry monitoring +- **Create pre-configured organizations** with projects and teams +- **Manage customer access** through integration tokens +- **Support multiple regions** (US and EU data residency) + +### 2. [OAuth Integration](/product/partnership-platform/oauth-integration/) + +Enable existing Sentry customers to connect their accounts to your platform through OAuth: + +- **Account linking** between your platform and Sentry organizations +- **Permission-based access** with configurable scopes +- **User-controlled permissions** with easy revocation +- **Seamless authentication flow** for your users + +## Benefits for Your Platform + +Integrating with Sentry's partnership platform provides several advantages: + +- **Enhanced developer experience** with built-in error monitoring +- **Reduced support burden** by helping customers debug issues faster +- **Competitive differentiation** with enterprise-grade monitoring +- **Revenue opportunities** through monitoring capabilities +- **Improved customer retention** with better application reliability + +## Getting Started + +If you're interested in integrating Sentry into your platform, our partnership team can help you get started. We'll work with you to: + +- Determine the best integration approach for your use case +- Set up the necessary API credentials and configurations +- Provide technical guidance and implementation support +- Establish the partnership agreement and terms + +## Contact Us + +Ready to explore partnership opportunities with Sentry? Reach out to our partnership platform team: + +**Email:** partnership-platform@sentry.io + +Our team will guide you through the integration process and help you leverage Sentry's monitoring capabilities to enhance your platform. \ No newline at end of file diff --git a/docs/product/partnership-platform/oauth-integration.mdx b/docs/product/partnership-platform/oauth-integration.mdx new file mode 100644 index 0000000000000..e778233a6aab4 --- /dev/null +++ b/docs/product/partnership-platform/oauth-integration.mdx @@ -0,0 +1,318 @@ +--- +title: "OAuth Integration" +description: "Learn how to integrate Sentry OAuth to allow existing customers to connect their Sentry accounts to your platform." +sidebar_order: 2 +--- + +# OAuth Integration + +Sentry's OAuth integration allows you to connect existing Sentry customers to your platform. This enables users to link their Sentry organizations with your product, providing seamless access to error monitoring and performance data. + +## Overview + +The OAuth flow enables: + +- **Account linking** between your platform and specific Sentry organizations +- **Permission-based access** with configurable API scopes +- **User-controlled permissions** with easy revocation +- **Seamless authentication** without requiring users to share credentials + +## User Experience Flow + +### 1. Account Linking + +Users sign into your platform and see a "Connect to Sentry" button with context about what permissions your product will have. + +### 2. Sentry Authentication + +Clicking the button opens a Sentry login modal where users authenticate with their Sentry account. + +### 3. Permission Confirmation + +After login, users see details about: +- Required permissions for your platform +- The specific Sentry organization being connected +- What actions your platform can perform + +### 4. Connection Complete + +Once confirmed, your platform receives an authorization code that can be exchanged for API tokens. + +## Implementation Steps + +### 1. Partner Registration + +Before implementing OAuth, Sentry must register your application. Contact our partnership team with: + +- **Client Name**: Your platform name +- **Redirect URIs**: Your OAuth callback URLs +- **Allowed Origins**: Your domain(s) +- **Home Page URL**: Your platform's homepage +- **Privacy Policy URL**: Your privacy policy +- **Terms and Conditions URL**: Your terms of service +- **Required Scopes**: APIs your platform needs to access + +### 2. Authorization Request + +Direct users to Sentry's authorization endpoint: + +``` +https://sentry.io/oauth/authorize/?client_id=YOUR_CLIENT_ID&response_type=code&scope=SCOPE1%20SCOPE2 +``` + +**Parameters:** +- `client_id`: Your registered client ID +- `response_type`: Always `code` +- `scope`: Space-separated list of required permissions + +**Example:** +``` +https://sentry.io/oauth/authorize/?client_id=0895306f2d310a075e82dff03cae9604c07e2c9465d4b990cc3f4c3010bb31d6&response_type=code&scope=project:read%20project:write +``` + +### 3. Handle Authorization Code + +After user approval, Sentry redirects to your callback URL with an authorization code: + +``` +https://your-platform.com/oauth/sentry/callback?code=2767ac2e734ce35fe648a5f7b831bbb82776e384bb172fbcea42c292dc195e20 +``` + +### 4. Exchange Code for Token + +Make a POST request to exchange the authorization code for an access token: + +```python +import requests + +TOKEN_URL = "https://sentry.io/oauth/token/" + +token_data = { + "client_id": "YOUR_CLIENT_ID", + "client_secret": "YOUR_CLIENT_SECRET", + "grant_type": "authorization_code", + "code": "AUTHORIZATION_CODE" +} + +response = requests.post(TOKEN_URL, data=token_data) +tokens = response.json() +``` + +**Response:** +```json +{ + "access_token": "8923f2eb3ec0fb9b328ccba6280e48debe119f5b5220273ffa13fb659b2d014a", + "refresh_token": "74dbc60782aed64814513804e75e5efa6aaa67e3163744c083c0eb77478edb8b", + "expires_in": 2591999, + "expires_at": "2024-11-27T23:20:21.054320Z", + "token_type": "bearer", + "scope": "org:read project:read", + "user": { + "id": "2", + "name": "user 1", + "email": "user1@test.com" + } +} +``` + +### 5. Refresh Tokens + +Access tokens expire every 8 hours. Use the refresh token to get new tokens: + +```python +refresh_data = { + "client_id": "YOUR_CLIENT_ID", + "client_secret": "YOUR_CLIENT_SECRET", + "grant_type": "refresh_token", + "refresh_token": "YOUR_REFRESH_TOKEN" +} + +response = requests.post(TOKEN_URL, data=refresh_data) +new_tokens = response.json() +``` + +## API Scopes + +Scopes define what permissions your application has. Common scopes include: + +- `org:read` - Read organization information +- `org:write` - Modify organization settings +- `project:read` - Read project data +- `project:write` - Create and modify projects +- `member:read` - Read organization members +- `member:write` - Manage organization members + +Required scopes depend on your use case and are documented in our [API documentation](https://docs.sentry.io/api/). + +## Using Access Tokens + +Include the access token in API requests using the Authorization header: + +```python +headers = { + "Authorization": f"Bearer {access_token}", + "Content-Type": "application/json" +} + +response = requests.get( + "https://sentry.io/api/0/organizations/", + headers=headers +) +``` + +## Organization Scoping + +A Sentry user can belong to multiple organizations. The access token only provides access to the specific organization the user selected during the OAuth flow. + +To get the connected organization: + +```python +# List organizations accessible with this token +response = requests.get( + "https://sentry.io/api/0/organizations/", + headers=headers +) +organizations = response.json() + +# The response will only include the organization the user connected +``` + +## Error Handling + +### Permission Errors (403) + +If your application requests permissions the user doesn't have: + +```python +if response.status_code == 403: + # Handle insufficient permissions + # You may need to request additional scopes or handle gracefully +``` + +### Token Expiration + +Handle expired tokens by refreshing: + +```python +if response.status_code == 401: + # Token expired, refresh it + new_tokens = refresh_access_token(refresh_token) + # Retry the original request with new token +``` + +## User Management + +### Revoking Access + +Users can revoke your application's access at any time through their Sentry account settings (Settings → Account → Authorized Applications). + +### Handling Revoked Access + +Monitor for 401 responses and handle gracefully: + +```python +if response.status_code == 401: + # Token may be revoked + # Prompt user to reconnect or handle appropriately +``` + +## Security Best Practices + +1. **Store tokens securely**: Encrypt tokens in your database +2. **Use HTTPS**: Always use HTTPS for OAuth flows +3. **Validate redirect URIs**: Ensure redirect URIs match your registered URLs +4. **Handle token expiration**: Implement automatic token refresh +5. **Monitor for revocations**: Handle cases where users revoke access + +## Example Implementation + +Here's a complete example of handling the OAuth flow: + +```python +from flask import Flask, request, redirect, session +import requests + +app = Flask(__name__) +app.secret_key = 'your-secret-key' + +CLIENT_ID = 'your-client-id' +CLIENT_SECRET = 'your-client-secret' +REDIRECT_URI = 'https://your-platform.com/oauth/sentry/callback' + +@app.route('/connect-sentry') +def connect_sentry(): + auth_url = ( + f"https://sentry.io/oauth/authorize/" + f"?client_id={CLIENT_ID}" + f"&response_type=code" + f"&scope=org:read%20project:read" + f"&redirect_uri={REDIRECT_URI}" + ) + return redirect(auth_url) + +@app.route('/oauth/sentry/callback') +def oauth_callback(): + code = request.args.get('code') + + # Exchange code for token + token_data = { + "client_id": CLIENT_ID, + "client_secret": CLIENT_SECRET, + "grant_type": "authorization_code", + "code": code + } + + response = requests.post("https://sentry.io/oauth/token/", data=token_data) + tokens = response.json() + + # Store tokens securely + session['sentry_access_token'] = tokens['access_token'] + session['sentry_refresh_token'] = tokens['refresh_token'] + + return "Successfully connected to Sentry!" + +@app.route('/sentry-data') +def get_sentry_data(): + access_token = session.get('sentry_access_token') + + headers = { + "Authorization": f"Bearer {access_token}", + "Content-Type": "application/json" + } + + # Get organization data + response = requests.get( + "https://sentry.io/api/0/organizations/", + headers=headers + ) + + if response.status_code == 401: + # Token expired, refresh it + refresh_token = session.get('sentry_refresh_token') + new_tokens = refresh_access_token(refresh_token) + session['sentry_access_token'] = new_tokens['access_token'] + + # Retry request + response = requests.get( + "https://sentry.io/api/0/organizations/", + headers={"Authorization": f"Bearer {new_tokens['access_token']}"} + ) + + return response.json() + +def refresh_access_token(refresh_token): + refresh_data = { + "client_id": CLIENT_ID, + "client_secret": CLIENT_SECRET, + "grant_type": "refresh_token", + "refresh_token": refresh_token + } + + response = requests.post("https://sentry.io/oauth/token/", data=refresh_data) + return response.json() +``` + +## Support + +For questions about OAuth integration or partnership setup, contact: +**Email:** partnership-platform@sentry.io \ No newline at end of file From 622516b686e05937b3a18807f8c601e8435cd299 Mon Sep 17 00:00:00 2001 From: Steven Eubank <47563310+smeubank@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:01:53 -0700 Subject: [PATCH 2/3] add link to platforms --- .../partnership-platform/account-provisioning-api.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product/partnership-platform/account-provisioning-api.mdx b/docs/product/partnership-platform/account-provisioning-api.mdx index f28485cb767bd..117b338e9c0c1 100644 --- a/docs/product/partnership-platform/account-provisioning-api.mdx +++ b/docs/product/partnership-platform/account-provisioning-api.mdx @@ -1,4 +1,4 @@ ---- +Sentry platform--- title: "Account Provisioning API" description: "Learn how to automatically provision Sentry organizations for your customers using our provisioning API." sidebar_order: 1 @@ -74,7 +74,7 @@ def generate_signature(data, secret_key): ### Supported Platforms -The `platform` field supports all Sentry platform identifiers, including: +The `platform` field supports all [Sentry platform identifiers](/platforms/), including: - `javascript`, `python`, `java`, `csharp`, `php`, `ruby`, `go`, `rust`, `swift`, `kotlin`, `dart`, and more ## Example Request @@ -212,4 +212,4 @@ Token permissions are defined in your partnership agreement. ## Support For questions about the provisioning API or partnership integration, contact: -**Email:** partnership-platform@sentry.io \ No newline at end of file +**Email:** partnership-platform@sentry.io From 2b33752ae2e1989a6716792b185528bf9dcf2a2f Mon Sep 17 00:00:00 2001 From: Steven Eubank <47563310+smeubank@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:06:35 -0700 Subject: [PATCH 3/3] add links to permissions and scopes docs --- docs/product/partnership-platform/oauth-integration.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product/partnership-platform/oauth-integration.mdx b/docs/product/partnership-platform/oauth-integration.mdx index e778233a6aab4..f1f4efe056a16 100644 --- a/docs/product/partnership-platform/oauth-integration.mdx +++ b/docs/product/partnership-platform/oauth-integration.mdx @@ -50,7 +50,7 @@ Before implementing OAuth, Sentry must register your application. Contact our pa - **Home Page URL**: Your platform's homepage - **Privacy Policy URL**: Your privacy policy - **Terms and Conditions URL**: Your terms of service -- **Required Scopes**: APIs your platform needs to access +- **Required Scopes**: APIs your platform needs to access. See [Permissions & Scopes](/api/permissions/) for a list of scopes. ### 2. Authorization Request @@ -133,7 +133,7 @@ new_tokens = response.json() ## API Scopes -Scopes define what permissions your application has. Common scopes include: +[Scopes](/api/permissions/) define what permissions your application has. Common scopes include: - `org:read` - Read organization information - `org:write` - Modify organization settings @@ -315,4 +315,4 @@ def refresh_access_token(refresh_token): ## Support For questions about OAuth integration or partnership setup, contact: -**Email:** partnership-platform@sentry.io \ No newline at end of file +**Email:** partnership-platform@sentry.io