Skip to content
Last updated

This guide explains how to build third-party applications that integrate with the Understory API on behalf of Understory customers. Third-party integrations use the OAuth 2.0 Authorization Code Grant flow, allowing your application to request access to a customer's Understory data with their explicit consent.

This is useful if you provide services that can use the data from Understory. Common examples are:

  • Marketplaces
  • Marketing tools
  • Accounting systems
Public Beta

Third-party integrations are currently in public beta. We are actively accepting new integrations and would love to work with you. However, some aspects of the integration process may change over the coming months as we learn and improve. We will communicate any changes in advance and work with you to ensure a smooth transition.

Getting Started

To build a third-party integration, you'll need OAuth 2.0 client credentials issued by Understory.

Contact us at integrations@understory.io with the following information.

FieldDescription
NameThe name of your application as it will appear to users during authorization
DescriptionA one or two sentence description of what your integration provides to the Understory customer
ScopesThe API scopes your application requires (e.g., booking.read, marketing.read). See Available Scopes for the complete list.
Redirect URIsThe callback URLs in your application where users will be redirected after they authorize access. This is a URL on your server that will receive the authorization code. For example: https://example.com/oauth/callback. You can register multiple URIs for different environments (development, staging, production).
Logo URIURL to your application's logo (displayed during authorization)
Policy URIURL to your privacy policy
Terms URIURL to your terms of service
App OwnerThe name of your company or organization
Contact EmailA contact email for integration-related communications

After review, you will receive your client ID and secret key via a secure link and you can start building your integration.

Keep your credentials secure

Your credentials, both client ID and secret key, must be kept confidential. Never expose them in client-side code, version control, or public repositories.

If your credentials have been compromised, reach out to integrations@understory.io and we will rotate them immediately.

OAuth 2.0 Authorization Code Grant

Third-party integrations use the OAuth 2.0 Authorization Code Grant flow. This is the industry-standard protocol for secure delegated authorization, used by platforms like Linear, Google, and Okta.

The flow consists of four main steps:

  1. Redirect the user to Understory's authorization endpoint
  2. Receive the authorization code via callback to your redirect URI
  3. Exchange the code for access and refresh tokens
  4. Use the access token to make API requests

Step 1: Initiate Authorization

Redirect the user to Understory's authorization endpoint to request access to their resources.

Include the following query parameters and remember to URL encode audience, redirect_uri, and scope.

FieldValue
response_typeLiteral string code
audienceLiteral string https://api.understory.io
client_idClient ID
redirect_uriOne of your registered redirect URIs
scopeApplicable space-separated scopes
stateA unique, random string to prevent CSRF attacks. Store this value and verify it in the callback.
https://api.auth.understory.io/oauth2/auth
  ?response_type=code
  &audience=https%3A%2F%2Fapi.understory.io
  &client_id=client-id
  &redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
  &scope=offline+marketing.read
  &state=random-string

This will show a consent screen with your application name, logo, and the permissions being requested. If they approve, they will be redirected to your specified redirect URI.

Step 2: Handle the Callback

After the user authorizes your application, Understory redirects them to your redirect_uri with an authorization code:

https://example.com/callback
  ?code=AUTHORIZATION_CODE
  &state=random-string
Verify the state parameter

Always verify that the state parameter matches the value you sent in Step 1. This protects against cross-site request forgery (CSRF) attacks.

If the user denies authorization or an error occurs, the callback will include error parameters instead. Read more in Error Handling.

https://example.com/callback
  ?error=access_denied
  &error_description=The+user+denied+the+request
  &state=random-string

Step 3: Exchange Code for Tokens

Exchange the authorization code for access and refresh tokens by making a POST request to the token endpoint https://api.auth.understory.io/oauth2/token. Use the following parameters provided in the body of the request.

FieldValue
grant_typeLiteral string authorization_code
client_idClient ID
client_secretSecret Key
redirect_uriThe registered redirect URI used to get the code
codeThe authorization code received in the callback
curl -X POST https://api.auth.understory.io/oauth2/token \
  -H "User-Agent: My-Company/Marketing-Automation-App" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=<client-id>" \
  -d "client_secret=<secret-key>" \
  -d "redirect_uri=https://example.com/oauth/callback" \
  -d "code=<authorization-code>"

If all parameters are valid you will receive the following response body with your token.

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjI0ZTUzZDkyLTY4ZmUt...",
  "expires_in": 3599,
  "refresh_token": "ory_rt_4dt-0JWm-9H2V4U1jfjUTCyJRbCZPSsvniMZQS18...",
  "scope": "offline marketing.read",
  "token_type": "bearer"
}
Authorization codes are single-use

Authorization codes can only be used once and expire shortly after being issued. Exchange them for tokens immediately.

Step 4: Store Credentials Securely

After receiving the tokens, store them securely:

  • Access tokens are short-lived (1 hour) and used to make API requests
  • Refresh tokens are long-lived (30 days) and used to obtain new access tokens without requiring user re-authorization
Security requirements
  • Store tokens encrypted at rest
  • Never log tokens or include them in error messages
  • Use secure, server-side storage (never browser localStorage for sensitive tokens)
  • Implement proper token rotation when using refresh tokens

Making API Requests

Include the access token in the Authorization header of your API requests.

curl -i -X GET \
  'https://api.understory.io/v1/marketing-consents?cursor=string&limit=100' \
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>'

Refreshing Access Tokens

When an access token expires, use the refresh token to obtain a new one without requiring user interaction:

curl -X POST https://api.auth.understory.io/oauth2/token \
  -H "User-Agent: My-Company/Marketing-Automation-App" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<refresh-token>" \
  -d "client_id=<client-id>" \
  -d "client_secret=<secret-key>"

Response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjI0ZTUzZDkyLTY4ZmUt...",
  "expires_in": 3599,
  "refresh_token": "ory_rt_XOnJ6xdZlbAAPBSSJ91uoGSYwJ3DVBsKFL-GEM5O...",
  "scope": "offline marketing.read",
  "token_type": "bearer"
}
Refresh token rotation

A new refresh token may be issued with each refresh request. Always store the latest refresh token received.

Error Handling

OAuth 2.0 errors follow the standard format defined in RFC 6749 Section 5.2:

{
  "error": "invalid_grant",
  "error_description": "The authorization code has expired"
}

Common errors include:

ErrorDescription
invalid_requestMissing or invalid parameters
invalid_clientClient authentication failed
invalid_grantAuthorization code or refresh token is invalid or expired
unauthorized_clientClient is not authorized to use this grant type
invalid_scopeRequested scope is invalid or exceeds granted permissions

Testing Your Integration

To test your third-party integration during development:

  1. Register development redirect URIs - When requesting credentials, include both production and development callback URLs (e.g., https://localhost:3000/oauth/callback for local testing).

  2. Use a test Understory account - Create a separate Understory account specifically for testing. This allows you to authorize your app and test the OAuth flow without affecting real customer data.

  3. Test the complete flow - Verify that your application can:

    • Redirect users to the authorization endpoint
    • Handle the callback with the authorization code
    • Exchange the code for tokens
    • Make API requests with the access token
    • Refresh tokens when they expire
  4. Handle edge cases - Test scenarios like:

    • User denies authorization
    • Invalid or expired authorization codes
    • Expired access tokens
    • Network failures during token exchange
No sandbox environment

Understory does not provide a separate sandbox environment. Use a dedicated test account and free experiences to safely test your integration without affecting production data or processing real payments.

See Testing to learn more.

Further Reading