# null Source: https://upstash.com/docs/README # Mintlify Starter Kit Click on `Use this template` to copy the Mintlify starter kit. The starter kit contains examples including * Guide pages * Navigation * Customizations * API Reference pages * Use of popular components ### šŸ‘©ā€šŸ’» Development Install the [Mintlify CLI](https://www.npmjs.com/package/mintlify) to preview the documentation changes locally. To install, use the following command ``` npm i -g mintlify ``` Run the following command at the root of your documentation (where mint.json is) ``` mintlify dev ``` ### šŸ˜Ž Publishing Changes Changes will be deployed to production automatically after pushing to the default branch. You can also preview changes using PRs, which generates a preview link of the docs. #### Troubleshooting * Mintlify dev isn't running - Run `mintlify install` it'll re-install dependencies. * Page loads as a 404 - Make sure you are running in a folder with `mint.json` # Add a Payment Method Source: https://upstash.com/docs/common/account/addapaymentmethod Upstash does not require a credit card for Free databases. However, for paid databases, you need to add at least one payment method. To add a payment method, follow these steps: 1. Click on your profile at the top right. 2. Select Ā `Account` from the dropdown menu. 3. Navigate to the `Billing` tab. 4. On the screen, click the `Add Your Card` button. 5. Enter your name and credit card information in the following form: You can enter multiple credit cards and set one of them as the default one. The payments will be charged from the default credit card. ## Payment Security Upstash does not store users' credit card information in its servers. We use Stripe Inc payment processing company to handle payments. You can read more about payment security in Stripe [here](https://stripe.com/docs/security/stripe). # Audit Logs Source: https://upstash.com/docs/common/account/auditlogs Audit logs give you a chronological set of activity records that have affected your databases and Upstash account. You can see the list of all activities on a single page. You can access your audit logs under `Account > Audit Logs` in your console: Here the `Source` column shows if the action has been called by the console or via an API key. The `Entity` column gives you the name of the resource that has been affected by the action. For example, when you delete a database, the name of the database will be shown here. Also, you can see the IP address which performed the action. ## Security You can track your audit logs to detect any unusual activity on your account and databases. When you suspect any security breach, you should delete the API key related to suspicious activity and inform us by emailing [support@upstash.com](mailto:support@upstash.com) ## Retention period After the retention period, the audit logs are deleted. The retention period for free databases is 7 days, for pay-as-you-go databases, it is 30 days, and for the Pro tier, it is one year. # AWS Marketplace Source: https://upstash.com/docs/common/account/awsmarketplace **Prerequisite** You need an Upstash account before subscribing on AWS, create one [here](https://console.upstash.com). Upstash is available on the AWS Marketplace, which is particularly beneficial for users who already get other services from AWS Marketplace and can consolidate Upstash under a single bill. You can search "Upstash" on AWS Marketplace or just click [here](https://aws.amazon.com/marketplace/pp/prodview-fssqvkdcpycco). Once you click subscribe, you will be prompted to select which personal or team account you wish to link with your AWS Subscription. Once your account is linked, regardless of which Upstash product you use, all of your usage will be billed to your AWS Account. You can also upgrade or downgrade your subscription through Upstash console. # Cost Explorer Source: https://upstash.com/docs/common/account/costexplorer The Cost Explorer pages allow you to view your current and previous months’ costs. To access the Cost Explorer, navigate to the left menu and select Account > Cost Explorer. Below is an example report: You can select a specific month to view the cost breakdown for that period. Here's the explanation of the fields in the report: **Request:** This represents the total number of requests sent to the database. **Storage:** This indicates the average size of the total storage consumed. Upstash database includes a persistence layer for data durability. For example, if you have 1 GB of data in your database throughout the entire month, this value will be 1 GB. Even if your database is empty for the first 29 days of the month and then expands to 30 GB on the last day, this value will still be 1 GB. **Cost:** This field represents the total cost of your database in US Dollars. > The values for the current month is updated hourly, so values can be stale up > to 1 hour. # Create an Account Source: https://upstash.com/docs/common/account/createaccount You can sign up for Upstash using your Amazon, Github or Google accounts. Alternatively, if you prefer not to use these authentication providers or want to sign up with a corporate email address, you can also sign up using email and password. We do not access your information other than: * Your email * Your name * Your profile picture and we never share your information with third parties. # Developer API Source: https://upstash.com/docs/common/account/developerapi Using Upstash API, you can develop applications that can create and manage Upstash databases and Upstash Vector Indexes. You can automate everything that you can do in the console. To use developer API, you need to create an API key in the console. Note: The Developer API is only available to native Upstash accounts. Accounts created via third-party platforms like Vercel or Fly.io are not supported. See [DevOps](/devops) for details. # Account and Billing FAQ Source: https://upstash.com/docs/common/account/faq ## How can I delete my account? You can delete your account from `Account` > `Settings` > `Delete Account`. You should first delete all your databases and clusters. After you delete your account, all your data and payment information will be deleted and you will not be able to recover it. ## How can I delete my credit card? You can delete your credit card from `Account` > `Billing` page. However, you should first add a new credit card to be able to delete the existing one. If you want to delete all of your payment information, you should delete your account. ## How can I change my email address? You can change your account e-mail address in `Account` > `Settings` page. In order to change your billing e-mail adress, please see `Account` > `Billing` page. If you encounter any issues, please contact us at [support@upstash.com](mailto:support@upstash.com) to change your email address. ## Can I set an upper spending limit, so I don't get surprises after an unexpected amount of high traffic? On Pay as You Go model, you can set a budget for your Redis instances. When your monthly cost reaches the max budget, we send an email to inform you and throttle your instance. You will not be charged beyond your set budget. To set the budget, you can go to the "Usage" tab of your Redis instance and click "Change Budget" under the cost metric. ## What happens if my payment fails? If a payment failure occurs, we will retry the payment three more times before suspending the account. During this time, you will receive email notifications about the payment failure. If the account is suspended, all resources in the account will be inaccessible. If you add a valid payment method after the account suspension, your account will be automatically unsuspended during the next payment attempt. ## What happens if I unsubscribe from AWS Marketplace but I don't have any other payment methods? We send a warning email three times before suspending an account. If no valid payment method is added, we suspend the account. Once the account is suspended, all resources within the account will be inaccessible. If you add a valid payment method after the account suspension, your account will be automatically unsuspended during the next system check. ## I have a question about my bill, who should I contact? Please contact us at [support@upstash.com](mailto:support@upstash.com). # Payment History Source: https://upstash.com/docs/common/account/paymenthistory The Payment History page gives you information about your payments. You can open your payment history in the left menu under Account > Payment History. Here an example report: You can download receipt. If one of your payments failed, you can retry your payment on this page. # Teams and Users Source: https://upstash.com/docs/common/account/teams Team management enables collaboration with other users. You can create a team and invite people to join by using their email addresses. Team members will have access to databases created under the team based on their assigned roles. ## Create Team You can create a team using the menu `Account > Teams`
> A user can create up to 5 teams. You can be part of even more teams but only > be the owner of 5 teams. If you need to own more teams please email us at > [support@upstash.com](mailto:support@upstash.com). You can still continue using your personal account or switch to a team. > The databases in your personal account are not shared with anyone. If you want > your database to be accessible by other users, you need to create it under a > team. ## Switch Team You need to switch to the team to create databases shared with other team members. You can switch to the team via the switch button in the team table. Or you can click your profile pic in the top right and switch to any team listed there. ## Add/Remove Team Member After switching to a team, if you are the Owner or an Admin of the team, you can add team members by navigating to `Account > Teams`. Simply enter their email addresses.It's not an issue if the email addresses are not yet registered with Upstash. Once the user registers with that email, they will gain access to the team. We do not send invitations; when you add a member, they become a member directly. You can also remove members from the same page. > Only Admins or the Owner can add/remove users. ## Roles While adding a team member, you will need to select a role. Here are the access rights associated with each role: * Admin: This role has full access, including the ability to add and remove members, manage databases, and payment methods. * Dev: This role can create, manage, and delete databases but cannot manage users or payment methods. * Finance: This role is limited to managing payment methods and cannot manage databases or users. * Owner: The Owner role has all the access rights of an Admin and, in addition to having the ability to delete the team. This role is automatically assigned to the user who created the team, and you cannot assign it to other members. > If you want to change a user's role, you will need to delete and re-add them with the desired access rights. ## Delete Team Only the original creator (owner) can delete a team. Also the team should not have any active databases, namely all databases under the team should be deleted first. To delete your team, first you need to switch your personal account then you can delete your team in the team list under `Account > Teams`. # Access Anywhere Source: https://upstash.com/docs/common/concepts/access-anywhere Upstash has integrated REST APIs into all its products to facilitate access from various runtime environments. This integration is particularly beneficial for edge runtimes like Cloudflare Workers and Vercel Edge, which do not permit TCP connections, and for serverless functions such as AWS Lambda, which are stateless and do not retain connection information between invocations. ### Rationale The absence of TCP connection support in edge runtimes and the stateless nature of serverless functions necessitate a different approach for persistent connections typically used in traditional server setups. The stateless REST API provided by Upstash addresses this gap, enabling consistent and reliable communication with data stores from these platforms. ### REST API Design The REST APIs for Upstash services are thoughtfully designed to align closely with the conventions of each product. This ensures that users who are already familiar with these services will find the interactions intuitive and familiar. Our API endpoints are self-explanatory, following standard REST practices to guarantee ease of use and seamless integration. ### SDKs for Popular Languages To enhance the developer experience, Upstash is developing SDKs in various popular programming languages. These SDKs simplify the process of integrating Upstash services with your applications by providing straightforward methods and functions that abstract the underlying REST API calls. ### Resources [Redis REST API Docs](https://upstash.com/docs/redis/features/restapi) [QStash REST API Docs](https://upstash.com/docs/qstash/api/authentication) [Redis SDK - Typescript](https://github.com/upstash/upstash-redis) [Redis SDK - Python](https://github.com/upstash/redis-python) [QStash SDK - Typescript](https://github.com/upstash/sdk-qstash-ts) # Global Replication Source: https://upstash.com/docs/common/concepts/global-replication Global Replication for Low Latency and High Availability Upstash Redis automatically replicates your data to the regions you choose, so your application stays fast and responsive-no matter where your users are. Add or remove regions from a database at any time with zero downtime. Each region acts as a replica, holding a copy of your data for low latency and high availability. *** ## Built for Modern Serverless Architectures In serverless computing, performance isn't just about fast code—it's also about fast, reliable data access from anywhere in the world. Whether you're using Vercel Functions, Cloudflare Workers, Fastly Compute, or Deno Deploy, your data layer needs to be as distributed and flexible as your compute for best performance. Upstash Global replicates your Redis data across multiple regions to: * Minimize round-trip latency * Guarantee high availability at scale ...even under heavy or dynamic workloads. Our HTTP-based RedisĀ® client is optimized for serverless environments and delivers consistent performance under high concurrency or variable workloads. As serverless platforms evolve with features like in-function concurrency (e.g. [Vercel's Fluid Compute](https://vercel.com/fluid)), you need a data layer that can keep up. Upstash Redis is a globally distributed, low-latency database that scales with your compute, wherever it runs. *** ## How Global Replication Works To minimize latency for read operations, we use a replica model. Our tests show sub-millisecond latency for read commands in the same AWS region as the Upstash RedisĀ® instance. **Read commands are automatically served from the geographically closest replica**: **Write commands go to the primary database** for consistency. After a successful write, they are replicated to all read replicas: *** ## Available Regions To create a globally distributed database, select a primary region and the number of read regions: * Select a primary region for most write operations for best performance. * Select read regions close to your users for optimized read speeds. Each request is then automatically served by the closest read replica for maximum performance and minimum latency: **You can create read replicas in the following regions:** * AWS US-East-1 (North Virginia) * AWS US-East-2 (Ohio) * AWS US-West-1 (North California) * AWS US-West-2 (Oregon) * AWS EU-West-1 (Ireland) * AWS EU-West-2 (London) * AWS EU-Central-1 (Frankfurt) * AWS AP-South-1 (Mumbai) * AWS AP-Northeast-1 (Tokyo) * AWS AP-Southeast-1 (Singapore) * AWS AP-Southeast-2 (Sydney) * AWS SA-East-1 (SĆ£o Paulo) Check out [our blog post](https://upstash.com/blog/global-database) to learn more about our global replication philosophy. You can also explore our [live benchmark](https://latency.upstash.com/) to see Upstash Redis latency from different locations around the world. # Scale to Zero Source: https://upstash.com/docs/common/concepts/scale-to-zero Only pay for what you really use. Traditionally, cloud services required users to predict their resource needs and provision servers or instances based on those predictions. This often led to over-provisioning to handle potential peak loads, resulting in paying for unused resources during periods of low demand. By *scaling to zero*, our pricing model aligns more closely with actual usage. ## Pay for usage You're only charged for the resources you actively use. When your application experiences low activity or no incoming requests, the system automatically scales down resources to a minimal level. This means you're no longer paying for idle capacity, resulting in cost savings. ## Flexibility "Scaling to zero" offers flexibility in scaling both up and down. As your application experiences traffic spikes, the system scales up resources to meet demand. Conversely, during quiet periods, resources scale down. ## Focus on Innovation Developers can concentrate on building and improving the application without constantly worrying about resource optimization. Upstash handles the scaling, allowing developers to focus on creating features that enhance user experiences. In essence, this aligns pricing with actual utilization, increases cost efficiency, and promotes a more sustainable approach to resource consumption. This model empowers businesses to leverage cloud resources without incurring unnecessary expenses, making cloud computing more accessible and attractive to a broader range of organizations. # Serverless Source: https://upstash.com/docs/common/concepts/serverless What do we mean by serverless? Upstash is a modern serverless data platform. But what do we mean by serverless? ## No Server Management In a serverless setup, developers don't need to worry about configuring or managing servers. We take care of server provisioning, scaling, and maintenance. ## Automatic Scaling As traffic or demand increases, Upstash automatically scales the required resources to handle the load. This means applications can handle sudden spikes in traffic without manual intervention. ## Granular Billing We charge based on the actual usage of resources rather than pre-allocated capacity. This can lead to more cost-effective solutions, as users only pay for what they consume. [Read more](/common/concepts/scale-to-zero) ## Stateless Functions In serverless architectures, functions are typically stateless. However, the traditional approach involves establishing long-lived connections to databases, which can lead to issues in serverless environments if connections aren't properly managed after use. Additionally, there are scenarios where TCP connections may not be feasible. Upstash addresses this issue by offering access via HTTP, a universally available protocol across all platforms. ## Rapid Deployment Fast iteration is the key to success in today's competitive environment. You can create a new Upstash database in seconds, with minimal required configuration. # Account & Teams Source: https://upstash.com/docs/common/help/account ## Create an Account You can sign up to Upstash using your Amazon, Github or Google accounts. Alternatively you can sign up using email/password registration if you don't want to use these auth providers, or you want to sign up using a corporate email address. We do not access your information other than: * Your email * Your name * Your profile picture and we never share your information with third parties. Team management allows you collaborate with other users. You can create a team and invite people to the team by email addresses. The team members will have access to the databases created under the team depending on their roles. ## Teams ### Create Team You can create a team using the menu `Account > Teams`
> A user can create up to 5 teams. You can be part of even more teams but only > be the owner of 5 teams. If you need to own more teams please email us at > [support@upstash.com](mailto:support@upstash.com). You can still continue using your personal account or switch to a team. > The databases in your personal account are not shared with anyone. If you want > your database to be accessible by other users, you need to create it under a > team. ### Switch Team You need to switch to the team to create databases shared with other team members. You can switch to the team via the switch button in the team table. Or you can click your profile pic in the top right and switch to any team listed there. ### Add/Remove Team Member Once you switched to a team, you can add team members in `Account > Teams` if you are Owner or Admin for of the team. Entering email will be enough. The email may not registered to Upstash yet, it is not a problem. Once the user registers with that email, he/she will be able to switch to the team. We do not send invitation, so when you add a member, he/she becomes a member directly. You can remove the members from the same page. > Only Admins or the Owner can add/remove users. ### Roles While adding a team member you need to select a role. Here the privileges of each role: * Admin: This role has full access including adding removing members, databases, payment methods. * Dev: This role can create, manage and delete databases. It can not manage users and payment methods. * Finance: This role can only manage payment methods. It can not manage the databases and users. * Owner: Owner has all the privileges that admin has. In addition he is the only person who can delete the team. This role is assigned to the user who created the team. So you can not create a member with Owner role. > If you want change role of a user, you need to delete and add again. ### Delete Team Only the original creator (owner) can delete a team. Also the team should not have any active databases, namely all databases under the team should be deleted first. To delete your team, first you need to switch your personal account then you can delete your team in the team list under `Account > Teams`. # Announcements Source: https://upstash.com/docs/common/help/announcements Upstash Announcements! Removal of GraphQL API and edge caching (Redis) (October 1, 2022) These two features have been already deprecated. We are planning to deactivate them completely on November 1st. We recommend use of REST API to replace GraphQL API and Global databases instead of Edge caching. Removal of strong consistency (Redis) (October 1, 2022) Upstash supported Strong Consistency mode for the single region databases. We decided to deprecate this feature because its effect on latency started to conflict with the performance expectations of Redis use cases. Moreover, we improved the consistency of replication to guarantee Read-Your-Writes consistency. Strong consistency will be disabled on existing databases on November 1st. #### Redis pay-as-you-go usage cap (October 1, 2022) We are increasing the max usage cap to \$160 from \$120 as of October 1st. This update is needed because of the increasing infrastructure cost due to replicating all databases to multiple instances. After your database exceeds the max usage cost, your database might be rate limited. #### Replication is enabled (Sep 29, 2022) All new and existing paid databases will be replicated to multiple replicas. Replication enables high availability in case of system and infrastructure failures. Starting from October 1st, we will gradually upgrade all databases without downtime. Free databases will stay single replica.
#### QStash Price Decrease (Sep 15, 2022) The price is \$1 per 100K requests.
#### [Pulumi Provider is available](https://upstash.com/blog/upstash-pulumi-provider) (August 4, 2022)
#### [QStash is released and announced](https://upstash.com/blog/qstash-announcement) (July 18, 2022)
#### [Announcing Upstash CLI](https://upstash.com/blog/upstash-cli) (May 16, 2022)
#### [Introducing Redis 6 Compatibility](https://upstash.com/blog/redis-6) (April 10, 2022)
#### Strong Consistency Deprecated (March 29, 2022) We have deprecated Strong Consistency mode for Redis databases due to its performance impact. This will not be available for new databases. We are planning to disable it on existing databases before the end of 2023. The database owners will be notified via email.
#### [Announcing Upstash Redis SDK v1.0.0](https://upstash.com/blog/upstash-redis-sdk-v1) (March 14, 2022)
#### Support for Google Cloud (June 8, 2021) Google Cloud is available for Upstash Redis databases. We initially support US-Central-1 (Iowa) region. Check the [get started guide](https://docs.upstash.com/redis/howto/getstartedgooglecloudfunctions).
#### Support for AWS Japan (March 1, 2021) ć“ć‚“ć«ć”ćÆę—„ęœ¬ Support for AWS Tokyo Region was the most requested feature by our users. Now our users can create their database in AWS Asia Pacific (Tokyo) region (ap-northeast-1). In addition to Japan, Upstash is available in the regions us-west-1, us-east-1, eu-west-1. Click [here](https://console.upstash.com) to start your database for free. Click [here](https://roadmap.upstash.com) to request new regions to be supported.
#### Vercel Integration (February 22, 2021) Upstash\&Vercel integration has been released. Now you are able to integrate Upstash to your project easily. We believe Upstash is the perfect database for your applications thanks to its: * Low latency data * Per request pricing * Durable storage * Ease of use Below are the resources about the integration: See [how to guide](https://docs.upstash.com/redis/howto/vercelintegration). See [integration page](https://vercel.com/integrations/upstash). See [Roadmap Voting app](https://github.com/upstash/roadmap) as a showcase for the integration. # Compliance Source: https://upstash.com/docs/common/help/compliance ## Upstash Legal & Security Documents * [Upstash Terms of Service](https://upstash.com/static/trust/terms.pdf) * [Upstash Privacy Policy](https://upstash.com/static/trust/privacy.pdf) * [Upstash Data Processing Agreement](https://upstash.com/static/trust/dpa.pdf) * [Upstash Technical and Organizational Security Measures](https://upstash.com/static/trust/security-measures.pdf) * [Upstash Subcontractors](https://upstash.com/static/trust/subprocessors.pdf) ## Is Upstash SOC2 Compliant? Upstash Redis databases under Pro and Enterprise support plans are SOC2 compliant. Check our [trust page](https://trust.upstash.com/) for details. ## Is Upstash ISO-27001 Compliant? We are in process of getting this certification. Contact us ([support@upstash.com](mailto:support@upstash.com)) to learn about the expected date. ## Is Upstash GDPR Compliant? Yes. For more information, see our [Privacy Policy](https://upstash.com/static/trust/privacy.pdf). We acquire DPAs from each [subcontractor](https://upstash.com/static/trust/subprocessors.pdf) that we work with. ## Is Upstash HIPAA Compliant? We are in process of getting this certification. Contact us ([support@upstash.com](mailto:support@upstash.com)) to learn about the expected date. ## Is Upstash PCI Compliant? Upstash does not store personal credit card information. We use Stripe for payment processing. Stripe is a certified PCI Service Provider Level 1, which is the highest level of certification in the payments industry. ## Does Upstash conduct vulnerability scanning and penetration tests? Yes, we use third party tools and work with pen testers. We share the results with Enterprise customers. Contact us ([support@upstash.com](mailto:support@upstash.com)) for more information. ## Does Upstash take backups? Yes, we take regular snapshots of the data cluster to the AWS S3 platform. ## Does Upstash encrypt data? Customers can enable TLS when creating a database or cluster, and we recommend this for production environments. Additionally, we encrypt data at rest upon customer request. # Integration with Third Parties & Partnerships Source: https://upstash.com/docs/common/help/integration ## Introduction In this guideline we will outline the steps to integrate Upstash into your platform (GUI or Web App) and allow your users to create and manage Upstash databases without leaving your interfaces. We will explain how to use OAuth2.0 as the underlying foundation to enable this access seamlessly. If your product or service offering utilizes Redis, Vector or QStash or if there is a common use case that your end users enable by leveraging these database resources, we invite you to be a partner with us. By integrating Upstash into your platform, you can offer a more complete package for your customers and become a one stop shop. This will also position yourself at the forefront of innovative cloud computing trends such as serverless and expand your customer base. This is the most commonly used partnership integration model that can be easily implemented by following this guideline. Recently [Cloudflare workers integration](https://blog.cloudflare.com/cloudflare-workers-database-integration-with-upstash/) is implemented through this methodology. For any further questions or partnership discussions please send us an email at [partnerships@upstash.com](mailto:partnerships@upstash.com) Before starting development to integrate Upstash into your product, please send an email to [partnerships@upstash.com](mailto:partnerships@upstash.com) for further assistance and guidance. **General Flow (High level user flow)** 1. User clicks **`Connect Upstash`**Ā button on your platform’s surface (GUI, Web App) 2. This initiates the OAuth 2.0 flow, which opens a new browser page displaying theĀ **`Upstash Login Page`**. 3. If this is an existing user, user logins with their Upstash credentials otherwise they can directly sign up for a new Upstash account. 4. Browser window redirects toĀ **`Your account has been connected`**Ā page and authentication window automatically closes. 5. After the user returns to your interface, they see their Upstash Account is now connected. ## Technical Design (SPA - Regular Web Application) 1. Users click `Connect Upstash` button from Web App. 2. Web App initiate Upstash OAuth 2.0 flow. Web App can use [Auth0 native libraries](https://auth0.com/docs/libraries). Please reach [partnerships@upstash.com](mailto:partnerships@upstash.com) to receive client id and callback url. 3. After user returns from OAuth 2.0 flow then web app will have JWT token. Web App can generate Developer Api key: ```bash curl -XPOST https://api.upstash.com/apikey \ -H "Authorization: Bearer JWT_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "APPNAME_API_KEY_TIMESTAMP" }' ``` 4. Web App need to save Developer Api Key to the backend. ## Technical Design ( GUI Apps ) 1. User clicksĀ **`Connect Upstash`**Ā button from web app. 2. Web app initiates Upstash OAuth 2.0 flow and it can useĀ **[Auth0 native libraries](https://auth0.com/docs/libraries)**. 3. App will open new browser: ``` https://auth.upstash.com/authorize?response_type=code&audience=upstash-api&scope=offline_access&client_id=XXXXXXXXXX&redirect_uri=http%3A%2F%2Flocalhost:3000 ``` Please reach [partnerships@upstash.com](mailto:partnerships@upstash.com) to receive client id. 4. After user authenticated Auth0 will redirect user to `localhost:3000/?code=XXXXXX` 5. APP can return some nice html response when Auth0 returns to `localhost:3000` 6. After getting `code` parameter from the URL query, GUI App will make http call to the Auth0 code exchange api. Example CURL request ```bash curl -XPOST 'https://auth.upstash.com/oauth/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data 'grant_type=authorization_code --data audience=upstash-api' \ --data 'client_id=XXXXXXXXXXX' \ --data 'code=XXXXXXXXXXXX' \ --data 'redirect_uri=localhost:3000' ``` Response: ```json { "access_token": "XXXXXXXXXX", "refresh_token": "XXXXXXXXXXX", "scope": "offline_access", "expires_in": 172800, "token_type": "Bearer" } ``` 7. After 6th Step the response will include `access_token`, it has 3 days TTL. GUI App will call Upstash API to get a developer api key: ```bash curl https://api.upstash.com/apikey -H "Authorization: Bearer JWT_KEY" -d '{ "name" : "APPNAME_API_KEY_TIMESTAMP" }' ``` 8. GUI App will save Developer Api key locally. Then GUI App can call any Upstash Developer API [developer.upstash.com/](https://developer.upstash.com/) ## Managing Resources After obtaining Upstash Developer Api key, your platform surface (web or GUI) can call Upstash API. For exampleĀ **[Create Database](https://developer.upstash.com/#create-database-global)**,Ā **[List Database](https://developer.upstash.com/#list-databases)** In this flow, you can ask users for region information and name of the database then can call Create Database API to complete the task Example CURL request: ```bash curl -X POST \ https://api.upstash.com/v2/redis/database \ -u 'EMAIL:API_KEY' \ -d '{"name":"myredis", "region":"global", "primary_region":"us-east-1", "read_regions":["us-west-1","us-west-2"], "tls": true}' ``` # Legal Source: https://upstash.com/docs/common/help/legal ## Upstash Legal Documents * [Upstash Terms of Service](https://upstash.com/trust/terms.pdf) * [Upstash Privacy Policy](https://upstash.com/trust/privacy.pdf) * [Upstash Subcontractors](https://upstash.com/trust/subprocessors.pdf) # Professional Support Source: https://upstash.com/docs/common/help/prosupport For all Upstash products, we manage everything for you and let you focus on more important things. If you ever need further help, our dedicated Professional Support team are here to ensure you get the most out of our platform, whether you’re just starting or scaling to new heights. Professional Support is strongly recommended especially for customers who use Upstash as part of their production systems. # Expert Guidance Get direct access to our team of specialists who can provide insights, troubleshooting, and best practices tailored to your unique use case. In any urgent incident you might have, our Support team will be standing by and ready to join you for troubleshooting. Professional Support package includes: * **Guaranteed Response Time:** Rapid Response Time SLA to urgent support requests, ensuring your concerns are addressed promptly with a **24/7 coverage**. * **Customer Onboarding:** A personalized session to guide you through utilizing our support services and reviewing your specific use case for a seamless start. * **Quarterly Use Case Review & Health Check:** On-request sessions every quarter to review your use case and ensure optimal performance. * **Dedicated Slack Channel:** Direct access to our team via a private Slack channel, so you can reach out whenever you need assistance. * **Incident Support:** Video call support during critical incidents to provide immediate help and resolution. * **Root Cause Analysis:** Comprehensive investigation and post-mortem analysis of critical incidents to identify and address the root cause. # Response Time SLA We understand that timely assistance is critical for production workloads, so your access to our Support team comes with 24/7 coverage and below SLA: | Severity | Response Time | | ------------------------------- | ------------- | | P1 - Production system down | 30 minutes | | P2 - Production system impaired | 2 hours | | P3 - Minor issue | 12 hours | | P4 - General guidance | 24 hours | ## How to Reach Out? As a Professional Support Customer, below are the **two methods** to reach out to Upstash Support Team, in case you need to utilize our services: #### Starting a Chat You will see a chatbox on the bottom right when viewing Upstash console, docs and website. Once you initiate a chat, Professional Support customers will be prompted to select a severity level: To be able to see these options in chat, remember to sign into your Upstash Account first. If you select "P1 - Production down, no workaround", or "P2 - Production impaired with workaround" options, you will be triggering an alert for our team to urgently step in. #### Sending an Email Sending an email with details to [support@upstash.com](mailto:support@upstash.com) is another way to submit a support request. In case of an urgency, sending an email with details by using "urgent" keyword in email subject is another alternative to alert our team about a possible incident. # Pricing For pricing and further details about Professional Support, please contact us at [support@upstash.com](mailto:support@upstash.com) # Uptime SLA Source: https://upstash.com/docs/common/help/sla This Service Level Agreement ("SLA") applies to the use of the Upstash services, offered under the terms of our Terms of Service or other agreement with us governing your use of Upstash. This SLA does not apply to Upstash services in the Upstash Free and Pay-as-you-go Tier. It is clarified that this SLA is subject to the terms of the Agreement, and does not derogate therefrom (capitalized terms, unless otherwise indicated herein, have the meaning specified in the Agreement). Upstash reserves the right to change the terms of this SLA by publishing updated terms on its website, such change to be effective as of the date of publication. ### Upstash Database SLA Upstash will use commercially reasonable efforts to make databases available with a Monthly Uptime Percentage of at least 99.99%. In the event any of the services do not meet the SLA, you will be eligible to receive a Service Credit as described below. | Monthly Uptime Percentage | Service Credit Percentage | | --------------------------------------------------- | ------------------------- | | Less than 99.99% but equal to or greater than 99.0% | 10% | | Less than 99.0% but equal to or greater than 95.0% | 30% | | Less than 95.0% | 60% | ### SLA Credits Service Credits are calculated as a percentage of the monthly bill (excluding one-time payments such as upfront payments) for the service in the affected region that did not meet the SLA. Uptime percentages are recorded and published in the [Upstash Status Page](https://status.upstash.com). To receive a Service Credit, you should submit a claim by sending an email to [support@upstash.com](mailto:support@upstash.com). Your credit request should be received by us before the end of the second billing cycle after the incident occurred. We will apply any service credits against future payments for the applicable services. At our discretion, we may issue the Service Credit to the credit card you used. Service Credits will not entitle you to any refund or other payment. A Service Credit will be applicable and issued only if the credit amount for the applicable monthly billing cycle is greater than one dollar (\$1 USD). Service Credits may not be transferred or applied to any other account. # Support & Contact Us Source: https://upstash.com/docs/common/help/support ## Community [Upstash Discord Channel](https://upstash.com/discord) is the best way to interact with the community. ## Team Regardless of your subscription plan, you can contact the team via [support@upstash.com](mailto:support@upstash.com) for technical support as well as questions and feedback. ## Follow Us Follow us on [X](https://x.com/upstash). ## Bugs & Issues You can help us improve Upstash by reporting issues, suggesting new features and giving general feedback in our [Community Github Repo](https://github.com/upstash/issues/issues/new). ## Enterprise Support Get [Enterprise Support](/common/help/prosupport) for your organization from the Upstash team. # Uptime Monitor Source: https://upstash.com/docs/common/help/uptime ## Status Page You can track the uptime status of Upstash databases in [Upstash Status Page](https://status.upstash.com) ## Latency Monitor You can see the average latencies for different regions in [Upstash Latency Monitoring](https://latency.upstash.com) page # Trials Source: https://upstash.com/docs/common/trials If you want to try Upstash paid and pro plans, we can offer **Free Trials**. Email us at [support@upstash.com](mailto:support@upstash.com) # Overview Source: https://upstash.com/docs/devops/cli/overview Manage Upstash resources in your terminal or CI. You can find the Github Repository [here](https://github.com/upstash/cli).
# Installation ## npm You can install upstash's cli directly from npm ```bash npm i -g @upstash/cli ``` It will be added as `upstash` to your system's path. ## Compiled binaries: `upstash` is also available from the [releases page](https://github.com/upstash/cli/releases/latest) compiled for windows, linux and mac (both intel and m1). # Usage ```bash > upstash Usage: upstash Version: development Description: Official cli for Upstash products Options: -h, --help - Show this help. -V, --version - Show the version number for this program. -c, --config - Path to .upstash.json file Commands: auth - Login and logout redis - Manage redis database instances team - Manage your teams and their members Environment variables: UPSTASH_EMAIL - The email you use on upstash UPSTASH_API_KEY - The api key from upstash ``` ## Authentication When running `upstash` for the first time, you should log in using `upstash auth login`. Provide your email and an api key. [See here for how to get a key.](https://docs.upstash.com/redis/howto/developerapi#api-development) As an alternative to logging in, you can provide `UPSTASH_EMAIL` and `UPSTASH_API_KEY` as environment variables. ## Usage Let's create a new redis database: ``` > upstash redis create --name=my-db --region=eu-west-1 Database has been created database_id a3e25299-132a-45b9-b026-c73f5a807859 database_name my-db database_type Pay as You Go region eu-west-1 type paid port 37090 creation_time 1652687630 state active password 88ae6392a1084d1186a3da37fb5f5a30 user_email andreas@upstash.com endpoint eu1-magnetic-lacewing-37090.upstash.io edge false multizone false rest_token AZDiASQgYTNlMjUyOTktMTMyYS00NWI5LWIwMjYtYzczZjVhODA3ODU5ODhhZTYzOTJhMTA4NGQxMTg2YTNkYTM3ZmI1ZjVhMzA= read_only_rest_token ApDiASQgYTNlMjUyOTktMTMyYS00NWI5LWIwMjYtYzczZjVhODA3ODU5O_InFjRVX1XHsaSjq1wSerFCugZ8t8O1aTfbF6Jhq1I= You can visit your database details page: https://console.upstash.com/redis/a3e25299-132a-45b9-b026-c73f5a807859 Connect to your database with redis-cli: redis-cli -u redis://88ae6392a1084d1186a3da37fb5f5a30@eu1-magnetic-lacewing-37090.upstash.io:37090 ``` ## Output Most commands support the `--json` flag to return the raw api response as json, which you can parse and automate your system. ```bash > upstash redis create --name=test2113 --region=us-central1 --json | jq '.endpoint' "gusc1-clean-gelding-30208.upstash.io" ``` # Authentication Source: https://upstash.com/docs/devops/developer-api/authentication Authentication for the Upstash Developer API The Upstash API requires API keys to authenticate requests. You can view and manage API keys at the Upstash Console. Upstash API uses HTTP Basic authentication. You should pass `EMAIL` and `API_KEY` as basic authentication username and password respectively. With a client such as `curl`, you can pass your credentials with the `-u` option, as the following example shows: ```curl curl https://api.upstash.com/v2/redis/database -u EMAIL:API_KEY ``` Replace `EMAIL` and `API_KEY` with your email and API key. # HTTP Status Codes Source: https://upstash.com/docs/devops/developer-api/http_status_codes The Upstash API uses the following HTTP Status codes: | Code | Description | | | ---- | ------------------------- | ------------------------------------------------------------------------------- | | 200 | **OK** | Indicates that a request completed successfully and the response contains data. | | 400 | **Bad Request** | Your request is invalid. | | 401 | **Unauthorized** | Your API key is wrong. | | 403 | **Forbidden** | The kitten requested is hidden for administrators only. | | 404 | **Not Found** | The specified kitten could not be found. | | 405 | **Method Not Allowed** | You tried to access a kitten with an invalid method. | | 406 | **Not Acceptable** | You requested a format that isn't JSON. | | 429 | **Too Many Requests** | You're requesting too many kittens! Slow down! | | 500 | **Internal Server Error** | We had a problem with our server. Try again later. | | 503 | **Service Unavailable** | We're temporarily offline for maintenance. Please try again later. | # Getting Started Source: https://upstash.com/docs/devops/developer-api/introduction Using Upstash API, you can develop applications that can create and manage Upstash products and resources. You can automate everything that you can do in the console. To use developer API, you need to create an API key in the console. ### Create an API key 1. Log in to the console then in the left menu click the `Account > Management API` link. 2. Click the `Create API Key` button. 3. Enter a name for your key. You can not use the same name for multiple keys. You need to download or copy/save your API key. Upstash does not remember or keep your API for security reasons. So if you forget your API key, it becomes useless; you need to create a new one.
You can create multiple keys. It is recommended to use different keys in different applications. By default one user can create up to 37 API keys. If you need more than that, please send us an email at [support@upstash.com](mailto:support@upstash.com) ### Deleting an API key When an API key is exposed (e.g. accidentally shared in a public repository) or not being used anymore; you should delete it. You can delete the API keys in `Account > API Keys` screen. ### Roadmap **Role based access:** You will be able to create API keys with specific privileges. For example you will be able to create a key with read-only access. **Stats:** We will provide reports based on usage of your API keys. # null Source: https://upstash.com/docs/devops/developer-api/redis/autoscaling # Create Backup Source: https://upstash.com/docs/devops/developer-api/redis/backup/create_backup POST https://api.upstash.com/v2/redis/create-backup/{id} This endpoint creates a backup for a Redis database. ## URL Parameters The ID of the Redis database ## Request Parameters Name of the backup ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/create-backup/{id} \ -u 'EMAIL:API_KEY' \ -d '{"name" : "backup_name"}' ``` ```python Python import requests data = '{"name" : "backup_name"}' response = requests.post('https://api.upstash.com/v2/redis/create-backup/{id}', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "name":"backup_name" }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/create-backup/{id}", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s ", bodyText); ``` ```json 200 OK "OK" ``` # Delete Backup Source: https://upstash.com/docs/devops/developer-api/redis/backup/delete_backup DELETE https://api.upstash.com/v2/redis/delete-backup/{id}/{backup_id} This endpoint deletes a backup of a Redis database. ## URL Parameters The ID of the Redis database The ID of the backup to delete ```shell curl curl -X DELETE \ https://api.upstash.com/v2/redis/delete-backup/:id/:backup_id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.delete('https://api.upstash.com/v2/redis/delete-backup/:id/:backup_id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("DELETE", "https://api.upstash.com/v2/redis/delete-backup/:id/:backup_id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s ", bodyText); ``` ```json 200 OK "OK" ``` # Disable Daily Backup Source: https://upstash.com/docs/devops/developer-api/redis/backup/disable_dailybackup PATCH https://api.upstash.com/v2/redis/disable-dailybackup/{id} This endpoint disables daily backup for a Redis database. ## URL Parameters The ID of the Redis database ```shell curl curl -X PATCH \ https://api.upstash.com/v2/redis/disable-dailybackup/{id} \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.patch('https://api.upstash.com/v2/redis/disable-dailybackup/{id}', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("PATCH", "https://api.upstash.com/v2/redis/disable-dailybackup/{id}", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s ", bodyText); ``` ```json 200 OK "OK" ``` # Enable Daily Backup Source: https://upstash.com/docs/devops/developer-api/redis/backup/enable_dailybackup PATCH https://api.upstash.com/v2/redis/enable-dailybackup/{id} This endpoint enables daily backup for a Redis database. ## URL Parameters The ID of the Redis database ```shell curl curl -X PATCH \ https://api.upstash.com/v2/redis/enable-dailybackup/{id} \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.patch('https://api.upstash.com/v2/redis/enable-dailybackup/{id}', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("PATCH", "https://api.upstash.com/v2/redis/enable-dailybackup/{id}", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s ", bodyText); ``` ```json 200 OK "OK" ``` # List Backup Source: https://upstash.com/docs/devops/developer-api/redis/backup/list_backup GET https://api.upstash.com/v2/redis/list-backup/{id} This endpoint lists all backups for a Redis database. ## URL Parameters The ID of the Redis database ## Response Parameters ID of the database Customer ID Name of the backup ID of the backup Creation time of the backup as Unix time State of the backup (e.g., completed) Size of the backup Daily backup status Hourly backup status ```shell curl curl -X GET \ https://api.upstash.com/v2/redis/list-backup/{id} \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.get('https://api.upstash.com/v2/redis/list-backup/{id}', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("GET", "https://api.upstash.com/v2/redis/list-backup/{id}", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s ", bodyText); ``` ```json 200 OK [ { "database_id":"6gceaafd-9627-4fa5-8g71-b3359g19a5g4", "customer_id":"customer_id", "name":"test2", "backup_id":"1768e55b-c137-4339-b46e-449dcd33a62e", "creation_time":1720186545, "state":"completed", "backup_size":0, "daily_backup":"false", "hourly_backup":"false" }, { "database_id":"6gceaafd-9627-4fa5-8g71-b3359g19a5g4", "customer_id":"customer_id", "name":"test1", "backup_id":"39310b84-21b3-45c3-5318-403553a2466d", "creation_time":1720096600, "state":"completed", "backup_size":0, "daily_backup":"false", "hourly_backup":"false" } ] ``` # Restore Backup Source: https://upstash.com/docs/devops/developer-api/redis/backup/restore_backup POST https://api.upstash.com/v2/redis/restore-backup/{id} This endpoint restores data from an existing backup. ## URL Parameters The ID of the Redis database ## Request Parameters ID of the backup to restore ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/restore-backup/{id} \ -u 'EMAIL:API_KEY' -d '{"backup_id" : "backup_id"}' ``` ```python Python import requests data = '{"backup_id" : "backup_id"}' response = requests.post('https://api.upstash.com/v2/redis/restore-backup/{id}', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "backup_id":"backup_id" }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/restore-backup/{id}", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s ", bodyText); ``` ```json 200 OK "OK" ``` # Create a Redis Database (Regional - DEPRECATED) Source: https://upstash.com/docs/devops/developer-api/redis/create_database POST https://api.upstash.com/v2/redis/database This endpoint creates a new regional Redis database. This behaviour is deprecated in favor of Global databases and support for it will be removed in the upcoming releases. ## Request Parameters Name of the database Region of the database.\ **Options:** `eu-west-1`, `us-east-1`, `us-west-1`, `ap-northeast-1` or `us-central1` Set true to enable tls. ## Response Parameters ID of the created database Name of the database Type of the database in terms of pricing model(Free, Pay as You Go or Enterprise) The region where database is hosted Database port for clients to connect Creation time of the database as Unix time State of database (active or deleted) Password of the database Email or team id of the owner of the database Endpoint URL of the database TLS/SSL is enabled or not ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/database \ -u 'EMAIL:API_KEY' \ -d '{"name":"myredis","region":"eu-west-1","tls": true}' ``` ```python Python import requests data = '{"name":"myredis","region":"eu-west-1","tls":true}' response = requests.post('https://api.upstash.com/v2/redis/database', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "name":"myredis", "region":"eu-west-1", "tls": true }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/database", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "database_id": "96ad0856-03b1-4ee7-9666-e81abd0349e1", "database_name": "MyRedis", "database_type": "Pay as You Go", "region": "eu-central-1", "port": 30143, "creation_time": 1658909671, "state": "active", "password": "038a8e27c45e43068d5f186085399884", "user_email": "example@upstash.com", "endpoint": "eu2-sought-mollusk-30143.upstash.io", "tls": true, "rest_token": "AXW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUxMDM4YThlMjdjNDVlNDMwNjhkNWYxODYwODUzOTk4ODQ=", "read_only_rest_token": "AnW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUx8sbmiEcMm9u7Ks5Qx-kHNiWr_f-iUXSIH8MlziKMnpY=" } ``` # Create a Redis Database (Global) Source: https://upstash.com/docs/devops/developer-api/redis/create_database_global POST https://api.upstash.com/v2/redis/database This endpoint creates a new Redis database. ## Request Parameters Name of the database Region of the database. Only valid option is `global`. Primary Region of the Global Database. Available regions: `us-east-1`, `us-west-1`, `us-west-2`, `eu-west-1`, `eu-central-1`, `ap-southeast-1`, `ap-southeast-2`, `sa-east-1` Array of Read Regions of the Database. Available regions: `us-east-1`, `us-west-1`, `us-west-2`, `eu-west-1`, `eu-central-1`, `ap-southeast-1`, `ap-southeast-2`, `ap-northeast-1`, `sa-east-1` Monthly budget of the database ## Response Parameters ID of the created database Name of the database Type of the database in terms of pricing model(Free, Pay as You Go or Enterprise) The region where database is hosted Database port for clients to connect Creation time of the database as Unix time State of database (active or deleted) Password of the database Email or team id of the owner of the database Endpoint URL of the database TLS is always enabled for new databases ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/database \ -u 'EMAIL:API_KEY' \ -d '{"name":"myredis", "region":"global", "primary_region":"us-east-1", "read_regions":["us-west-1","us-west-2"], "tls": true}' ``` ```python Python import requests data = '{"name":"myredis", "region":"global", "primary_region":"us-east-1", "read_regions":["us-west-1","us-west-2"], "tls":true}' response = requests.post('https://api.upstash.com/v2/redis/database', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "name":"myredis", "region":"global", "primary_region"":"us-east-1", "read_regions":["us-west-1","us-west-2"], "tls": true }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/database", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "database_id": "93e3a3e-342c-4683-ba75-344c08ae143b", "database_name": "global-test", "database_type": "Pay as You Go", "region": "global", "type": "paid", "port": 32559, "creation_time": 1674596896, "state": "active", "password": "dd1803832a2746309e118373549e574d", "user_email": "support@upstash.com", "endpoint": "steady-stud-32559.upstash.io", "tls": false, "rest_token": "AX8vACQgOTMyY2UyYy00NjgzLWJhNzUtMzQ0YzA4YWUxNDNiZMyYTI3NDYzMDllMTE4MzczNTQ5ZTU3NGQ=", "read_only_rest_token": "An8vACQg2UtMzQyYy00NjgzLWJhNzUtMzQ0YzA4YBVsUsyn19xDnTAvjbsiq79GRDrURNLzIYIOk=" } ``` # Delete Database Source: https://upstash.com/docs/devops/developer-api/redis/delete_database DELETE https://api.upstash.com/v2/redis/database/{id} This endpoint deletes a database. ## URL Parameters The ID of the database to be deleted ```shell curl curl -X DELETE \ https://api.upstash.com/v2/redis/database/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.delete('https://api.upstash.com/v2/redis/database/:id' auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("DELETE", "https://api.upstash.com/v2/redis/database/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Disable Auto Upgrade Source: https://upstash.com/docs/devops/developer-api/redis/disable_autoscaling POST https://api.upstash.com/v2/redis/disable-autoupgrade/{id} This endpoint disables Auto Upgrade for given database. ## URL Parameters The ID of the database to disable auto upgrade ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/disable-autoupgrade/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.post('https://api.upstash.com/v2/redis/disable-autoupgrade/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/disable-autoupgrade/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` `json 200 OK "OK" ` # Disable Eviction Source: https://upstash.com/docs/devops/developer-api/redis/disable_eviction POST https://api.upstash.com/v2/redis/disable-eviction/{id} This endpoint disables eviction for given database. ## URL Parameters The ID of the database to disable eviction ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/disable-eviction/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.post('https://api.upstash.com/v2/redis/disable-eviction/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/disable-eviction/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Enable Auto Upgrade Source: https://upstash.com/docs/devops/developer-api/redis/enable_autoscaling POST https://api.upstash.com/v2/redis/enable-autoupgrade/{id} This endpoint enables Auto Upgrade for given database. ## URL Parameters The ID of the database to enable auto upgrade ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/enable-autoupgrade/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.post('https://api.upstash.com/v2/redis/enable-autoupgrade/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/enable-autoupgrade/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Enable Eviction Source: https://upstash.com/docs/devops/developer-api/redis/enable_eviction POST https://api.upstash.com/v2/redis/enable-eviction/{id} This endpoint enables eviction for given database. ## URL Parameters The ID of the database to enable eviction ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/enable-eviction/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.post('https://api.upstash.com/v2/redis/enable-eviction/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/enable-eviction/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Enable TLS Source: https://upstash.com/docs/devops/developer-api/redis/enable_tls POST https://api.upstash.com/v2/redis/enable-tls/{id} This endpoint enables tls on a database. ## URL Parameters The ID of the database to rename ## Response Parameters ID of the created database Name of the database Type of the database in terms of pricing model\ `Free`, `Pay as You Go` or `Enterprise` The region where database is hosted Database port for clients to connect Creation time of the database as Unix time State of database\ `active` or `deleted` Password of the database Email or team id of the owner of the database Endpoint URL of the database TLS/SSL is enabled or not ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/enable-tls/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.post('https://api.upstash.com/v2/redis/enable-tls/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/enable-tls/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "database_id": "96ad0856-03b1-4ee7-9666-e81abd0349e1", "cluster_id": "dea1f974", "database_name": "MyRedis", "database_type": "Pay as You Go", "region": "eu-central-1", "port": 30143, "creation_time": 1658909671, "state": "active", "password": "49665a1710f3434d8be008aab50f38d2", "user_email": "example@upstash.com", "endpoint": "eu2-sought-mollusk-30143.upstash.io", "tls": true, } ``` # Get Database Source: https://upstash.com/docs/devops/developer-api/redis/get_database GET https://api.upstash.com/v2/redis/database/{id} This endpoint gets details of a database. ## Request The ID of the database to reset password Set to `hide` to remove credentials from the response. ## Response ID of the created database Name of the database Type of the database in terms of pricing model(Free, Pay as You Go or Enterprise) The region where database is hosted Database port for clients to connect Creation time of the database as Unix time State of database (active or deleted) Password of the database Email or team id of the owner of the database Endpoint URL of the database TLS/SSL is enabled or not Token for rest based communication with the database Read only token for rest based communication with the database Max number of concurrent clients can be opened on this database currently Max size of a request that will be accepted by the database currently(in bytes) Total disk size limit that can be used for the database currently(in bytes) Max size of an entry that will be accepted by the database currently(in bytes) Max size of a memory the database can use(in bytes) Max daily bandwidth can be used by the database(in bytes) Max number of commands can be sent to the database per second Total number of commands can be sent to the database ```shell curl curl -X GET \ https://api.upstash.com/v2/redis/database/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.get('https://api.upstash.com/v2/redis/database/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("GET", "https://api.upstash.com/v2/redis/database/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "database_id": "96ad0856-03b1-4ee7-9666-e81abd0349e1", "database_name": "MyRedis", "database_type": "Pay as You Go", "region": "eu-central-1", "port": 30143, "creation_time": 1658909671, "state": "active", "password": "038a8e27c45e43068d5f186085399884", "user_email": "example@upstash.com", "endpoint": "eu2-sought-mollusk-30143.upstash.io", "tls": true, "rest_token": "AXW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUxMDM4YThlMjdjNDVlNDMwNjhkNWYxODYwODUzOTk4ODQ=", "read_only_rest_token": "AnW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUx8sbmiEcMm9u7Ks5Qx-kHNiWr_f-iUXSIH8MlziKMnpY=", "db_max_clients": 1000, "db_max_request_size": 1048576, "db_disk_threshold": 107374182400, "db_max_entry_size": 104857600, "db_memory_threshold": 1073741824, "db_daily_bandwidth_limit": 53687091200, "db_max_commands_per_second": 1000, "db_request_limit": 9223372036854775808 } ``` # Get Database Stats Source: https://upstash.com/docs/devops/developer-api/redis/get_database_stats GET https://api.upstash.com/v2/redis/stats/{id} This endpoint gets detailed stats of a database. ## URL Parameters The ID of the database ## Response Parameters Timestamp indicating when the measurement was taken. Total number of connections momentarily Timestamp indicating when the measurement was taken. Total number keys exists in the database Timestamp indicating when the measurement was taken. Throughput seen on the database connections Timestamp indicating when the measurement was taken. Throughput seen on the database connections for write requests Timestamp indicating when the measurement was taken. Throughput seen on the database connections for read requests Timestamp indicating when the measurement was taken. Total amount of this usage of the database Timestamp indicating when the measurement was taken. Maximum server latency observed in the last hour Timestamp indicating when the measurement was taken. Minimum server latency observed in the last hour Timestamp indicating when the measurement was taken. The average read latency value measured in the last hour Timestamp indicating when the measurement was taken. The 99th percentile server read latency observed in the last hour Timestamp indicating when the measurement was taken. The average write latency value measured in the last hour Timestamp indicating when the measurement was taken. The 99th percentile server write latency observed in the last hour Timestamp indicating when the measurement was taken. Total number requests made to the database that are hit Timestamp indicating when the measurement was taken. Total number requests made to the database that are miss Timestamp indicating when the measurement was taken. Total number read requests made to the database Timestamp indicating when the measurement was taken. Total number write requests made to the database Timestamp indicating when the measurement was taken. Total number requests made to the database on the corresponding day The total daily bandwidth usage (in bytes). Timestamp indicating when the measurement was taken. The total bandwidth size for that specific timestamp A list of the days of the week for the measurement Timestamp indicating when the measurement was taken. The billing amount for that specific date. Total number of daily produced commands Total number of daily consumed commands The total number of requests made in the current month. The total number of read requests made in the current month. The total number of write requests made in the current month. The total amount of storage used (in bytes) in the current month. Total cost of the database in the current month Total number of produce commands in the current month Total number of consume commands in the current month ```shell curl curl -X GET \ https://api.upstash.com/v2/redis/stats/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.get('https://api.upstash.com/v2/redis/stats/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("GET", "https://api.upstash.com/v2/redis/stats/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "connection_count": [ { "x": "2023-05-22 10:59:23.426 +0000 UTC", "y": 320 }, ... ], "keyspace": [ { "x": "2023-05-22 10:59:23.426 +0000 UTC", "y": 344725564 }, ... ], "throughput": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 181.88333333333333 }, ... ], "produce_throughput": null, "consume_throughput": null, "diskusage": [ { "x": "2023-05-22 10:59:23.426 +0000 UTC", "y": 532362818323 }, ... ], "latencymean": [ { "x": "2023-05-22 10:59:23.426 +0000 UTC", "y": 0.176289 }, ... ], "read_latency_mean": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 0 }, ... ], "read_latency_99": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 0 }, ... ], "write_latency_mean": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 0 }, ... ], "write_latency_99": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 0 }, ... ], "hits": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 0 }, ... ], "misses": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 0 }, ... ], "read": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 82.53333333333333 }, ... ], "write": [ { "x": "2023-05-22 11:00:23.426 +0000 UTC", "y": 99.35 }, ... ], "dailyrequests": [ { "x": "2023-05-18 11:58:23.534505371 +0000 UTC", "y": 68844080 }, ... ], "days": [ "Thursday", "Friday", "Saturday", "Sunday", "Monday" ], "dailybilling": [ { "x": "2023-05-18 11:58:23.534505371 +0000 UTC", "y": 145.72694911244588 }, ... ], "dailybandwidth": 50444740913, "bandwidths": [ { "x": "2023-05-18 11:58:23.534505371 +0000 UTC", "y": 125391861729 }, ... ], "dailyproduce": null, "dailyconsume": null, "total_monthly_requests": 1283856937, "total_monthly_read_requests": 1034567002, "total_monthly_write_requests": 249289935, "total_monthly_storage": 445942383672, "total_monthly_billing": 222.33902763855485, "total_monthly_produce": 0, "total_monthly_consume": 0 } ``` # List Databases Source: https://upstash.com/docs/devops/developer-api/redis/list_databases GET https://api.upstash.com/v2/redis/databases This endpoint list all databases of user. ## Response Parameters ID of the database Name of the database Type of the database in terms of pricing model\ `Free`, `Pay as You Go` or `Enterprise` The region where database is hosted Database port for clients to connect Creation time of the database as Unix time State of database\ `active` or `deleted` Password of the database Email or team id of the owner of the database Endpoint URL of the database TLS/SSL is enabled or not Token for rest based communication with the database Read only token for rest based communication with the database ```shell curl curl -X GET \ https://api.upstash.com/v2/redis/databases \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.get('https://api.upstash.com/v2/redis/databases', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("GET", "https://api.upstash.com/v2/redis/databases", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK [ { "database_id": "96ad0856-03b1-4ee7-9666-e81abd0349e1", "database_name": "MyRedis", "database_type": "Pay as You Go", "region": "eu-central-1", "port": 30143, "creation_time": 1658909671, "state": "active", "password": "038a8e27c45e43068d5f186085399884", "user_email": "example@upstash.com", "endpoint": "eu2-sought-mollusk-30143.upstash.io", "tls": true, "rest_token": "AXW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUxMDM4YThlMjdjNDVlNDMwNjhkNWYxODYwODUzOTk4ODQ=", "read_only_rest_token": "AnW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUx8sbmiEcMm9u7Ks5Qx-kHNiWr_f-iUXSIH8MlziKMnpY=" } ] ``` # Move To Team Source: https://upstash.com/docs/devops/developer-api/redis/moveto_team POST https://api.upstash.com/v2/redis/move-to-team This endpoint moves database under a target team ## URL Parameters The ID of the target team The ID of the database to be moved ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/move-to-team \ -u 'EMAIL:API_KEY' \ -d '{"team_id": "6cc32556-0718-4de5-b69c-b927693f9282","database_id": "67b6af16-acb2-4f00-9e38-f6cb9bee800d"}' ``` ```python Python import requests data = '{"team_id": "6cc32556-0718-4de5-b69c-b927693f9282","database_id": "67b6af16-acb2-4f00-9e38-f6cb9bee800d"}' response = requests.post('https://api.upstash.com/v2/redis/move-to-team', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "team_id": "6cc32556-0718-4de5-b69c-b927693f9282", "database_id": "67b6af16-acb2-4f00-9e38-f6cb9bee800d" }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/move-to-team", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` `json 200 OK "OK" ` # Rename Database Source: https://upstash.com/docs/devops/developer-api/redis/rename_database POST https://api.upstash.com/v2/redis/rename/{id} This endpoint renames a database. ## URL Parameters The ID of the database to be renamed ## Request Parameters The new name of the database ## Response Parameters ID of the created database New name of the database Type of the database in terms of pricing model\ `Free`, `Pay as You Go` or `Enterprise` The region where database is hosted List of primary regions in the database cluster List of all regions in the database cluster Primary region of the database cluster Database port for clients to connect Creation time of the database as Unix time Allocated budget for database operations State of database\ `active` or `deleted` Password of the database Email or team id of the owner of the database Endpoint URL of the database TLS/SSL is enabled or not Whether entry eviction is enabled Automatic upgrade capability status Strong consistency mode status Reserved price per region for enterprise plans Unix timestamp of next scheduled backup Database state Full-access REST token Read-only REST token Maximum allowed concurrent client connections Maximum request size in bytes Resource allocation tier Database storage engine type Disk storage limit in bytes Maximum entry size in bytes Memory usage limit in bytes Connection idle timeout in nanoseconds Lua script execution timeout in nanoseconds Lua script execution credits per minute Store connection idle timeout in nanoseconds Maximum load operations per second Maximum commands processed per second Maximum allowed requests Database-level eviction policy status Access Control List enablement status Default user access status in ACL ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/rename/:id \ -u 'EMAIL:API_KEY' -d '{"name":"MyRedis_new_name"}' ``` ```python Python import requests data = '{"name":"MyRedis_new_name"}' response = requests.post('https://api.upstash.com/v2/redis/rename/:id', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "name":"MyRedis_new_name" }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/rename/:id", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "database_id": 96ad0856-03b1-4ee7-9666-e81abd0349e1, "database_name": "MyRedis_new_name", "database_type": "Pay as You Go", "region": "global", "type": "paid", "primary_members": [ "eu-central-1" ], "all_members": [ "eu-central-1" ], "primary_region": "eu-central-1", "port": 6379, "creation_time": 1727087321, "budget": 100, "state": "active", "password": ā€œ***ā€, "user_email": ā€œa**@upstash.com", "endpoint": ā€œall-foxe-22421.upstash.io", "tls": true, "eviction": true, "auto_upgrade": false, "consistent": false, "reserved_per_region_price": 0, "next_daily_backup_time": 1741120356, "modifying_state": "", "rest_token": ā€œ***ā€, "read_only_rest_token": ā€œ***ā€, "db_max_clients": 1000, "db_max_request_size": 1048576, "db_resource_size": "L", "db_type": "pebble", "db_disk_threshold": 107374182400, "db_max_entry_size": 104857600, "db_memory_threshold": 3221225472, "db_conn_idle_timeout": 21600000000000, "db_lua_timeout": 250000000, "db_lua_credits_per_min": 10000000000, "db_store_max_idle": 900000000000, "db_max_loads_per_sec": 1000000, "db_max_commands_per_second": 1000, "db_request_limit": 9223372036854776000, "db_eviction": true, "db_acl_enabled": "false", "db_acl_default_user_status": "true" } ``` ``` ``` # Reset Password Source: https://upstash.com/docs/devops/developer-api/redis/reset_password POST https://api.upstash.com/v2/redis/reset-password/{id} This endpoint updates the password of a database. ## Request The ID of the database to reset password ## Response ID of the created database Name of the database Type of the database in terms of pricing model\ `Free`, `Pay as You Go` or `Enterprise` The region where database is hosted Database port for clients to connect Creation time of the database as Unix time State of database\ `active` or `deleted` Password of the database Email or team id of the owner of the database Endpoint URL of the database TLS/SSL is enabled or not ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/reset-password/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.post('https://api.upstash.com/v2/redis/reset-password/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/reset-password/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "database_id": "96ad0856-03b1-4ee7-9666-e81abd0349e1", "cluster_id": "dea1f974", "database_name": "MyRedis", "database_type": "Pay as You Go", "region": "eu-central-1", "port": 30143, "creation_time": 1658909671, "state": "active", "password": "49665a1710f3434d8be008aab50f38d2", "user_email": "example@upstash.com", "endpoint": "eu2-sought-mollusk-30143.upstash.io", "tls": true, "consistent": false, "pool_id": "f886c7f3", "rest_token": "AXW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUxNDk2NjVhMTcxMGYzNDM0ZDhiZTAwOGFhYjUwZjM4ZDI=", "read_only_rest_token": "AnW_ASQgOTZhZDA4NTYtMDNiMS00ZWU3LTk2NjYtZTgxYWJkMDM0OWUxB5sRhCROkPsxozFcDzDgVGRAxUI7UUr0Y6uFB7jMIOI=" } ``` # Update Regions (Global) Source: https://upstash.com/docs/devops/developer-api/redis/update_regions POST https://api.upstash.com/v2/redis/update-regions/{id} Update the regions of global database ## Request The ID of your database Array of read regions of the database **Options:** `us-east-1`, `us-west-1`, `us-west-2`, `eu-west-1`, `eu-central-1`, `ap-southeast-1`, `ap-southeast-2`, `sa-east-1` ```shell curl curl -X POST \ https://api.upstash.com/v2/redis/update-regions/:id \ -u 'EMAIL:API_KEY' \ -d '{ "read_regions":["us-west-1"] }' ``` ```python Python import requests data = '{"read_regions":["eu-west-1"]}' response = requests.post('https://api.upstash.com/v2/redis/database', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{, "read_regions":["us-west-1"] }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/redis/read-regions/:id", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Add Team Member Source: https://upstash.com/docs/devops/developer-api/teams/add_team_member POST https://api.upstash.com/v2/teams/member This endpoint adds a new team member to the specified team. ## Request Parameters Id of the team to add the member to Email of the new team member Role of the new team member
**Options:** `admin`, `dev` or `finance`
## Response Parameters ID of the created team Name of the created team Email of the new team member Role of the new team member ```shell curl curl -X POST \ https://api.upstash.com/v2/teams/member \ -u 'EMAIL:API_KEY' \ -d '{"team_id":"95849b27-40d0-4532-8695-d2028847f823","member_email":"example@upstash.com","member_role":"dev"}' ``` ```python Python import requests data = '{"team_id":"95849b27-40d0-4532-8695-d2028847f823","member_email":"example@upstash.com","member_role":"dev"}' response = requests.post('https://api.upstash.com/v2/teams/member', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "team_id":"95849b27-40d0-4532-8695-d2028847f823", "member_email":"example@upstash.com", "member_role":"dev" }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/teams/member", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "team_id": "95849b27-40d0-4532-8695-d2028847f823", "team_name": "test_team_name", "member_email": "example@upstash.com", "member_role": "dev" } ``` # Create Team Source: https://upstash.com/docs/devops/developer-api/teams/create_team POST https://api.upstash.com/v2/team This endpoint creates a new team. ## Request Parameters Name of the new team Whether to copy existing credit card information to team or not\ Options: `true` or `false` ## Response Parameters ID of the created team Name of the created team Whether creditcard information added to team during creation or not ```shell curl curl -X POST \ https://api.upstash.com/v2/team \ -u 'EMAIL:API_KEY' \ -d '{"team_name":"myteam","copy_cc":true}' ``` ```python Python import requests data = '{"team_name":"myteam","copy_cc":true}' response = requests.post('https://api.upstash.com/v2/team', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "team_name":"myteam", "copy_cc":true }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/team", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "team_id": "75b471f2-15a1-47b0-8ce5-12a57682bfc9", "team_name": "test_team_name_2", "copy_cc": true } ``` # Delete Team Source: https://upstash.com/docs/devops/developer-api/teams/delete_team DELETE https://api.upstash.com/v2/team/{id} This endpoint deletes a team. ## URL Parameters The ID of the team to delete ## Response Parameters "OK" ```shell curl curl -X DELETE \ https://api.upstash.com/v2/team/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.delete('https://api.upstash.com/v2/team/:id' auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("DELETE", "https://api.upstash.com/v2/team/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Delete Team Member Source: https://upstash.com/docs/devops/developer-api/teams/delete_team_member DELETE https://api.upstash.com/v2/teams/member This endpoint deletes a team member from the specified team. ## Request Parameters Id of the team to add the member to Email of the new team member ## Response Parameters "OK" ```shell curl curl -X DELETE \ https://api.upstash.com/v2/teams/member \ -u 'EMAIL:API_KEY' \ -d '{"team_id":"95849b27-40d0-4532-8695-d2028847f823","member_email":"example@upstash.com"}' ``` ```python Python import requests data = '{"team_id":"95849b27-40d0-4532-8695-d2028847f823","member_email":"example@upstash.com"}' response = requests.delete('https://api.upstash.com/v2/teams/member', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "team_id":"95849b27-40d0-4532-8695-d2028847f823", "member_email":"example@upstash.com" }`) req, err := http.NewRequest("DELETE", "https://api.upstash.com/v2/teams/member", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Get Team Members Source: https://upstash.com/docs/devops/developer-api/teams/get_team_members GET https://api.upstash.com/v2/teams/{team_id} This endpoint list all members of a team. ## Request Parameters ID of the team ## Response Parameters ID of the team Name of the team Email of the team member Role of the team member ```shell curl curl -X GET \ https://api.upstash.com/v2/teams/:id \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.get('https://api.upstash.com/v2/teams/:id', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("GET", "https://api.upstash.com/v2/teams/:id", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK [ { "team_id": "3423cb72-e50d-43ec-a9c0-f0f359941223", "team_name": "test_team_name_2", "member_email": "example@upstash.com", "member_role": "dev" }, { "team_id": "3423cb72-e50d-43ec-a9c0-f0f359941223", "team_name": "test_team_name_2", "member_email": "example_2@upstash.com", "member_role": "owner" } ] ``` # List Teams Source: https://upstash.com/docs/devops/developer-api/teams/list_teams GET https://api.upstash.com/v2/teams This endpoint lists all teams of user. ## Response Parameters ID of the created team Role of the user in this team Name of the created team Whether creditcard information added to team during creation or not ```shell curl url -X GET \ https://api.upstash.com/v2/teams \ -u 'EMAIL:API_KEY' ``` ```python Python import requests response = requests.get('https://api.upstash.com/v2/teams', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("GET", "https://api.upstash.com/v2/teams", nil) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK [ { "team_id": "95849b27-40d0-4532-8695-d2028847f823", "team_name": "test_team_name", "member_role": "owner", "copy_cc": true } ] ``` # Create Index Source: https://upstash.com/docs/devops/developer-api/vector/create_index POST https://api.upstash.com/v2/vector/index This endpoint creates an index. ## Request Parameters Name of the index. Region of the database.\ **Options:** `eu-west-1`, `us-east-1`, Similarity function that's used to calculate the distance between two vectors.\ **Options:** `COSINE`, `EUCLIDIAN`, `DOT_PRODUCT` The amount of values in a single vector. The payment plan of your index.\ **Options:** `payg`, `fixed` The payment plan of your index.\ **Options:** `BGE_SMALL_EN_V1_5`, `BGE_BASE_EN_V1_5`, `BGE_LARGE_EN_V1_5`, `BGE_M3`, `BERT_BASE_UNCASED`, `UAE_Large_V1`, `ALL_MINILM_L6_V2`, `MXBAI_EMBED_LARGE_V1` ## Response Parameters The associated ID of the owner of the index Unique ID of the index The name of the index. Similarity function that's used to calculate the distance between two vectors The amount of values in a single vector The REST endpoint of the index The REST authentication token for the index The REST authentication read only token for the index The payment plan of the index The region where the index is currently deployed. The number of maximum that your index can contain. The number of maximum update operations you can perform in a day. Only upsert operations are included in update count. The number of maximum query operations you can perform in a day. Only query operations are included in query count. The maximum amount of monthly bandwidth for the index. Unit is bytes. `-1` if the limit is unlimited. The number of maximum write operations you can perform per second. Only upsert operations are included in write count. The number of maximum query operations you can perform per second. Only query operations are included in query count. The number of maximum vectors in a read operation. Query and fetch operations are included in read operations. The number of maximum vectors in a write operation. Only upsert operations are included in write operations. The amount of maximum size for the total metadata sizes in your index. Monthly pricing of your index. Only available for fixed and pro plans. The creation time of the vector index in UTC as unix timestamp. The predefined embedding model to vectorize your plain text. ```shell curl curl -X POST https://api.upstash.com/v2/vector/index \ -u 'EMAIL:API_KEY' \ -d '{ "name": "myindex", "region": "eu-west-1", "similarity_function": "COSINE", "dimension_count": 1536 }' \ ``` ```javascript JavaScript const axios = require('axios'); const postData = { name: "myindex", region: "eu-west-1", similarity_function: "COSINE", dimension_count: 1536, }; const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, headers: { 'Content-Type': 'application/json', }, }; axios.post('https://api.upstash.com/v2/vector/index', postData, config) .then((response) => { console.log('Response:', response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests data = '{"name":"myindex","region":"eu-west-1","similarity_function":"COSINE","dimension_count":1536}' response = requests.post('https://api.upstash.com/v2/vector/index', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader('{ "name":"myindex", "region":"eu-west-1", "similarity_function":"COSINE", "dimension_count":1536}' ) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/vector/index", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "customer_id": "test@upstash.com", "id": "0639864f-ece6-429c-8118-86a287b0e808", "name": "myindex", "similarity_function": "COSINE", "dimension_count": 5, "embedding_model": "BGE_SMALL_EN_V1_5" "endpoint": "test-index-3814-eu1-vector.upstash.io", "token": "QkZGMk5heGltdW0tdXBkYXRlZC0zNzM1LWV1MkFkbWlOeGZGZ1J5Wm1GdE5tTXhNQzB1TmpsbExUb3hOekF0TVRJbFpqMTJORFUxTm1GZw==", "read_only_token": "QkZGRk1heGltdW0tdXBkYXRlZC0zNzM1LWV1MnJlYWRvbmx5TmtaZ05qS3JNWVV0Wm1aZ01pMDBOV1poTHRob05qY3RNR0U0TkRjejNqazJU" "type": "paid", "region": "eu-west-1", "max_vector_count": 400000000, "max_daily_updates": -1, "max_daily_queries": -1, "max_monthly_bandwidth": -1, "max_writes_per_second": 1000, "max_query_per_second": 1000, "max_reads_per_request": 1000, "max_writes_per_request": 1000, "max_total_metadata_size": 53687091200, "creation_time": 1707313165 } ``` # Delete Index Source: https://upstash.com/docs/devops/developer-api/vector/delete_index DELETE https://api.upstash.com/v2/vector/index/{id} This endpoint deletes an index. ## Request Parameters The unique ID of the index to be deleted. ## Response Parameters `"OK"` on successfull deletion operation. ```shell curl curl -X DELETE https://api.upstash.com/v2/vector/index/0639864f-ece6-429c-8118-86a287b0e808 \ -u 'EMAIL:API_KEY' ``` ```javascript JavaScript const axios = require('axios'); const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, }; const url = 'https://api.upstash.com/v2/vector/index/0639864f-ece6-429c-8118-86a287b0e808'; axios.delete(url, config) .then((response) => { console.log('Deleted successfully', response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests id="0639864f-ece6-429c-8118-86a287b0e808" response = requests.delete(f"https://api.upstash.com/v2/vector/index/{id}", auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("DELETE", "https://api.upstash.com/v2/vector/index/0639864f-ece6-429c-8118-86a287b0e808", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Get Index Source: https://upstash.com/docs/devops/developer-api/vector/get_index GET https://api.upstash.com/v2/vector/index/{id} This endpoint returns the data associated to a index. ## Request Parameters The unique ID of the index to fetch. ## Response Parameters The associated ID of the owner of the index Unique ID of the index The name of the index. Similarity function that's used to calculate the distance between two vectors The amount of values in a single vector The REST endpoint of the index The REST authentication token for the index The REST authentication read only token for the index The payment plan of the index The region where the index is currently deployed. The number of maximum that your index can contain. The number of maximum update operations you can perform in a day. Only upsert operations are included in update count. The number of maximum query operations you can perform in a day. Only query operations are included in query count. The maximum amount of monthly bandwidth for the index. Unit is bytes. `-1` if the limit is unlimited. The number of maximum write operations you can perform per second. Only upsert operations are included in write count. The number of maximum query operations you can perform per second. Only query operations are included in query count. The number of maximum vectors in a read operation. Query and fetch operations are included in read operations. The number of maximum vectors in a write operation. Only upsert operations are included in write operations. The amount of maximum size for the total metadata sizes in your index. Monthly pricing of your index. Only available for fixed and pro plans. The creation time of the vector index in UTC as unix timestamp. ```shell curl curl -X GET https://api.upstash.com/v2/vector/index/0639864f-ece6-429c-8118-86a287b0e808 \ -u 'EMAIL:API_KEY' \ ``` ```javascript JavaScript const axios = require('axios'); const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, }; const url = 'https://api.upstash.com/v2/vector/index/0639864f-ece6-429c-8118-86a287b0e808'; axios.get(url, config) .then((response) => { console.log(response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests id = "0639864f-ece6-429c-8118-86a287b0e808" response = requests.post(f"https://api.upstash.com/v2/vector/index/{id}", auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/vector/index/0639864f-ece6-429c-8118-86a287b0e808", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK { "customer_id": "test@upstash.com", "id": "0639864f-ece6-429c-8118-86a287b0e808", "name": "myindex", "similarity_function": "COSINE", "dimension_count": 5, "endpoint": "test-index-3814-eu1-vector.upstash.io", "token": "QkZGMk5heGltdW0tdXBkYXRlZC0zNzM1LWV1MkFkbWlOeGZGZ1J5Wm1GdE5tTXhNQzB1TmpsbExUb3hOekF0TVRJbFpqMTJORFUxTm1GZw==", "read_only_token": "QkZGRk1heGltdW0tdXBkYXRlZC0zNzM1LWV1MnJlYWRvbmx5TmtaZ05qS3JNWVV0Wm1aZ01pMDBOV1poTHRob05qY3RNR0U0TkRjejNqazJU" "type": "paid", "region": "eu-west-1", "max_vector_count": 400000000, "max_daily_updates": -1, "max_daily_queries": -1, "max_monthly_bandwidth": -1, "max_writes_per_second": 1000, "max_query_per_second": 1000, "max_reads_per_request": 1000, "max_writes_per_request": 1000, "max_total_metadata_size": 53687091200, "creation_time": 1707313165 } ``` # List Indices Source: https://upstash.com/docs/devops/developer-api/vector/list_indices GET https://api.upstash.com/v2/vector/index/ This endpoint returns the data related to all indices of an account as a list. ## Request Parameters This endpoint doesn't require any additional data. ## Response Parameters The associated ID of the owner of the index Unique ID of the index The name of the index. Similarity function that's used to calculate the distance between two vectors The amount of values in a single vector The REST endpoint of the index The payment plan of the index The region where the index is currently deployed. The number of maximum that your index can contain. The number of maximum update operations you can perform in a day. Only upsert operations are included in update count. The number of maximum query operations you can perform in a day. Only query operations are included in query count. The maximum amount of monthly bandwidth for the index. Unit is bytes. `-1` if the limit is unlimited. The number of maximum write operations you can perform per second. Only upsert operations are included in write count. The number of maximum query operations you can perform per second. Only query operations are included in query count. The number of maximum vectors in a read operation. Query and fetch operations are included in read operations. The number of maximum vectors in a write operation. Only upsert operations are included in write operations. The amount of maximum size for the total metadata sizes in your index. Monthly pricing of your index. Only available for fixed and pro plans. The creation time of the vector index in UTC as unix timestamp. ```shell curl curl -X GET \ https://api.upstash.com/v2/vector/index \ -u 'EMAIL:API_KEY' \ ``` ```javascript JavaScript const axios = require('axios'); const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, }; const url = 'https://api.upstash.com/v2/vector/index'; axios.get(url, config) .then((response) => { console.log(response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests response = requests.get('https://api.upstash.com/v2/vector/index', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("GET", "https://api.upstash.com/v2/vector/index") if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK [ { "customer_id": "test@upstash.com", "id": "0639864f-ece6-429c-8118-86a287b0e808", "name": "myindex", "similarity_function": "COSINE", "dimension_count": 5, "endpoint": "test-index-3814-eu1-vector.upstash.io", "token": "QkZGMk5heGltdW0tdXBkYXRlZC0zNzM1LWV1MkFkbWlOeGZGZ1J5Wm1GdE5tTXhNQzB1TmpsbExUb3hOekF0TVRJbFpqMTJORFUxTm1GZw==", "read_only_token": "QkZGRk1heGltdW0tdXBkYXRlZC0zNzM1LWV1MnJlYWRvbmx5TmtaZ05qS3JNWVV0Wm1aZ01pMDBOV1poTHRob05qY3RNR0U0TkRjejNqazJU" "type": "paid", "region": "eu-west-1", "max_vector_count": 400000000, "max_daily_updates": -1, "max_daily_queries": -1, "max_monthly_bandwidth": -1, "max_writes_per_second": 1000, "max_query_per_second": 1000, "max_reads_per_request": 1000, "max_writes_per_request": 1000, "max_total_metadata_size": 53687091200, "creation_time": 1707313165 } ] ``` # Rename Index Source: https://upstash.com/docs/devops/developer-api/vector/rename_index POST https://api.upstash.com/v2/vector/index/{id}/rename This endpoint is used to change the name of an index. ## Request Parameters The unique ID of the index to be deleted. The new name of the index. ## Response Parameters `"OK"` on successfull deletion operation. ```shell curl curl -X POST \ https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/rename \ -u 'EMAIL:API_KEY' \ -d '{"name":"myindex"}' ``` ```javascript JavaScript const axios = require('axios'); const postData = { name: "myindex", }; const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, headers: { 'Content-Type': 'application/json', }, }; const url = 'https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/rename'; axios.post(url, postData, config) .then((response) => { console.log('Rename successful:', response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests data = '{"name":"myindex"}' response = requests.post('https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/rename', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "name":"myindex", }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/rename", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Reset Index Passwords Source: https://upstash.com/docs/devops/developer-api/vector/reset_index_passwords POST https://api.upstash.com/v2/vector/index/{id}/reset-password This endpoint is used to reset regular and readonly tokens of an index. ## Request Parameters The unique ID of the index to reset the password for.. ## Response Parameters `"OK"` on successfull deletion operation. ```shell curl curl -X POST \ https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/reset-password \ -u 'EMAIL:API_KEY' \ ``` ```javascript JavaScript const axios = require('axios'); const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, headers: { 'Content-Type': 'application/json', }, }; const url = 'https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/reset-password'; axios.post(url, {}, config) // Sending an empty object as data since no payload is required. .then((response) => { console.log('Operation successful:', response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests response = requests.post('https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/reset-password', auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} req, err := http.NewRequest("POST", "https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/reset-password") if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Set Index Plan Source: https://upstash.com/docs/devops/developer-api/vector/set_index_plan POST https://api.upstash.com/v2/vector/index/{id}/setplan This endpoint is used to change the plan of an index. ## Request Parameters The unique ID of the index to be deleted. The new plan for the index. ## Response Parameters `"OK"` on successfull deletion operation. ```shell curl curl -X POST \ https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/setplan \ -u 'EMAIL:API_KEY' \ -d '{"target_plan":"fixed"}' ``` ```javascript JavaScript const axios = require('axios'); const postData = { target_plan: "fixed", }; const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, headers: { 'Content-Type': 'application/json', }, }; const url = 'https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/setplan'; axios.post(url, postData, config) .then((response) => { console.log('Plan set successfully:', response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests data = '{"target_plan":"fixed"}' response = requests.post('https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/setplan', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "target_plan":"fixed", }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/setplan", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Transfer Index Source: https://upstash.com/docs/devops/developer-api/vector/transfer_index POST https://api.upstash.com/v2/vector/index/{id}/transfer This endpoint is used to transfer an index to another team. ## Request Parameters The unique ID of the index to be deleted. The ID of the target account. If the target is a team, then use the format `team:`, else if the target is your personal account use the format ``. ## Response Parameters `"OK"` on successfull deletion operation. ```shell curl curl -X POST \ https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/transfer \ -u 'EMAIL:API_KEY' \ -d '{"target_account":"team:team-id-1"}' ``` ```javascript JavaScript const axios = require('axios'); const postData = { target_account: "team:team-id-1", }; const config = { auth: { username: 'EMAIL', password: 'API_KEY', }, headers: { 'Content-Type': 'application/json', }, }; const url = 'https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/transfer'; axios.post(url, postData, config) .then((response) => { console.log('Transfer successful:', response.data); }) .catch((error) => { console.error('Error:', error); }); ``` ```python Python import requests data = '{"target_account":"team:team-id-1"}' response = requests.post('https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/transfer', data=data, auth=('EMAIL', 'API_KEY')) response.content ``` ```go Go client := &http.Client{} var data = strings.NewReader(`{ "target_account":"team:team-id-1", }`) req, err := http.NewRequest("POST", "https://api.upstash.com/v2/vector/index/14841111-b834-4788-925c-04ab156d1123/transfer", data) if err != nil { log.Fatal(err) } req.SetBasicAuth("email", "api_key") resp, err := client.Do(req) if err != nil { log.Fatal(err) } bodyText, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s\n", bodyText); ``` ```json 200 OK "OK" ``` # Overview Source: https://upstash.com/docs/devops/pulumi/overview The Upstash Pulumi Provider lets you manage [Upstash](https://upstash.com) Redis resources programmatically. You can find the Github Repository [here](https://github.com/upstash/pulumi-upstash). ## Installing This package is available for several languages/platforms: ### Node.js (JavaScript/TypeScript) To use from JavaScript or TypeScript in Node.js, install using either `npm`: ```bash npm install @upstash/pulumi ``` or `yarn`: ```bash yarn add @upstash/pulumi ``` ### Python To use from Python, install using `pip`: ```bash pip install upstash_pulumi ``` ### Go To use from Go, use `go get` to grab the latest version of the library: ```bash go get github.com/upstash/pulumi-upstash/sdk/go/... ``` ## Configuration The following configuration points are available for the `upstash` provider: * `upstash:apiKey` (environment: `UPSTASH_API_KEY`) - the API key for `upstash`. Can be obtained from the [console](https://console.upstash.com). * `upstash:email` (environment: `UPSTASH_EMAIL`) - owner email of the resources ## Some Examples ### TypeScript: ```typescript import * as pulumi from "@pulumi/pulumi"; import * as upstash from "@upstash/pulumi"; // multiple redis databases in a single for loop for (let i = 0; i < 5; i++) { new upstash.RedisDatabase("mydb" + i, { databaseName: "pulumi-ts-db" + i, region: "eu-west-1", tls: true, }); } ``` ### Go: ```go package main import ( "github.com/pulumi/pulumi/sdk/v3/go/pulumi" "github.com/upstash/pulumi-upstash/sdk/go/upstash" ) func main() { pulumi.Run(func(ctx *pulumi.Context) error { createdTeam, err := upstash.NewTeam(ctx, "exampleTeam", &upstash.TeamArgs{ TeamName: pulumi.String("pulumi go team"), CopyCc: pulumi.Bool(false), TeamMembers: pulumi.StringMap{ "": pulumi.String("owner"), "": pulumi.String("dev"), }, }) if err != nil { return err } return nil }) } ``` # null Source: https://upstash.com/docs/devops/terraform # upstash_qstash_endpoint_data Source: https://upstash.com/docs/devops/terraform/data_sources/upstash_qstash_endpoint_data ```hcl example.tf data "upstash_qstash_endpoint_data" "exampleQStashEndpointData" { endpoint_id = resource.upstash_qstash_endpoint.exampleQStashEndpoint.endpoint_id } ``` ## Schema ### Required Topic Id that the endpoint is added to ### Read-Only Unique QStash Endpoint ID The ID of this resource. Unique QStash Topic Name for Endpoint # upstash_qstash_schedule_data Source: https://upstash.com/docs/devops/terraform/data_sources/upstash_qstash_schedule_data ```hcl example.tf data "upstash_qstash_schedule_data" "exampleQStashScheduleData" { schedule_id = resource.upstash_qstash_schedule.exampleQStashSchedule.schedule_id } ``` ## Schema ### Required Unique QStash Schedule ID for requested schedule ### Read-Only Body to send for the POST request in string format. Needs escaping () double quotes. Creation time for QStash Schedule Cron string for QStash Schedule Destination for QStash Schedule. Either Topic ID or valid URL Forward headers to your API The ID of this resource. Start time for QStash Scheduling. Retries for QStash Schedule requests. # upstash_qstash_topic_data Source: https://upstash.com/docs/devops/terraform/data_sources/upstash_qstash_topic_data ```hcl example.tf data "upstash_qstash_topic_data" "exampleQstashTopicData" { topic_id = resource.upstash_qstash_topic.exampleQstashTopic.topic_id } ``` ## Schema ### Required Unique QStash Topic ID for requested topic ### Read-Only Endpoints for the QStash Topic The ID of this resource. Name of the QStash Topic # upstash_redis_database_data Source: https://upstash.com/docs/devops/terraform/data_sources/upstash_redis_database_data ```hcl example.tf data "upstash_redis_database_data" "exampleDBData" { database_id = resource.upstash_redis_database.exampleDB.database_id } ``` ## Schema ### Required Unique Database ID for created database ### Read-Only Upgrade to higher plans automatically when it hits quotas Creation time of the database Name of the database Type of the database Daily bandwidth limit for the database Disk threshold for the database Max clients for the database Max commands per second for the database Max entry size for the database Max request size for the database Memory threshold for the database Database URL for connection The ID of this resource. Password of the database Port of the endpoint Primary region for the database (Only works if region='global'. Can be one of \[us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2]) Rest Token for the database. Read regions for the database (Only works if region='global' and primary\_region is set. Can be any combination of \[us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2], excluding the one given as primary.) Region of the database. Possible values are: `global`, `eu-west-1`, `us-east-1`, `us-west-1`, `ap-northeast-1` , `eu-central1` Rest Token for the database. State of the database When enabled, data is encrypted in transit. (If changed to false from true, results in deletion and recreation of the resource) User email for the database # upstash_team_data Source: https://upstash.com/docs/devops/terraform/data_sources/upstash_team_data ```hcl example.tf data "upstash_team_data" "teamData" { team_id = resource.upstash_team.exampleTeam.team_id } ``` ## Schema ### Required Unique Cluster ID for created cluster ### Read-Only Whether Credit Card is copied The ID of this resource. Members of the team. (Owner must be specified, which is the owner of the api key.) Name of the team # Overview Source: https://upstash.com/docs/devops/terraform/overview The Upstash Terraform Provider lets you manage Upstash Redis resources programmatically. You can find the Github Repository for the Terraform Provider [here](https://github.com/upstash/terraform-provider-upstash). ## Installation ```hcl terraform { required_providers { upstash = { source = "upstash/upstash" version = "x.x.x" } } } provider "upstash" { email = var.email api_key = var.api_key } ``` `email` is your registered email in Upstash. `api_key` can be generated from Upstash Console. For more information please check our [docs](https://docs.upstash.com/howto/developerapi). ## Create Database Using Terraform Here example code snippet that creates database: ```hcl resource "upstash_redis_database" "redis" { database_name = "db-name" region = "eu-west-1" tls = "true" multi_zone = "false" } ``` ## Import Resources From Outside of Terraform To import resources created outside of the terraform provider, simply create the resource in .tf file as follows: ```hcl resource "upstash_redis_database" "redis" {} ``` after this, you can run the command: ``` terraform import upstash_redis_database.redis ``` Above example is given for an Upstash Redis database. You can import all of the resources by changing the resource type and providing the resource id. You can check full spec and [doc from here](https://registry.terraform.io/providers/upstash/upstash/latest/docs). ## Support, Bugs Reports, Feature Requests If you need support then you can ask your questions Upstash Team in [upstash.com](https://upstash.com) chat widget. There is also discord channel available for community. [Please check here](https://docs.upstash.com/help/support) for more information. # upstash_qstash_endpoint Source: https://upstash.com/docs/devops/terraform/resources/upstash_qstash_endpoint Create and manage QStash endpoints. ```hcl example.tf resource "upstash_qstash_endpoint" "exampleQStashEndpoint" { url = "https://***.***" topic_id = resource.upstash_qstash_topic.exampleQstashTopic.topic_id } ``` ## Schema ### Required Topic ID that the endpoint is added to URL of the endpoint ### Read-Only Unique QStash endpoint ID The ID of this resource. Unique QStash topic name for endpoint # upstash_qstash_schedule Source: https://upstash.com/docs/devops/terraform/resources/upstash_qstash_schedule Create and manage QStash schedules. ```hcl example.tf resource "upstash_qstash_schedule" "exampleQStashSchedule" { destination = resource.upstash_qstash_topic.exampleQstashTopic.topic_id cron = "* * * * */2" # or simply provide a link # destination = "https://***.***" } ``` ## Schema ### Required Cron string for QStash Schedule Destination for QStash Schedule. Either Topic ID or valid URL ### Optional Body to send for the POST request in string format. Needs escaping () double quotes. Callback URL for QStash Schedule. Content based deduplication for QStash Scheduling. Content type for QStash Scheduling. Deduplication ID for QStash Scheduling. Delay for QStash Schedule. Forward headers to your API Start time for QStash Scheduling. Retries for QStash Schedule requests. ### Read-Only Creation time for QStash Schedule. The ID of this resource. Unique QStash Schedule ID for requested schedule # upstash_qstash_topic Source: https://upstash.com/docs/devops/terraform/resources/upstash_qstash_topic Create and manage QStash topics ```hcl example.tf resource "upstash_qstash_topic" "exampleQStashTopic" { name = "exampleQStashTopicName" } ``` ## Schema ### Required Name of the QStash topic ### Read-Only Endpoints for the QStash topic The ID of this resource. Unique QStash topic ID for requested topic # upstash_redis_database Source: https://upstash.com/docs/devops/terraform/resources/upstash_redis_database Create and manage Upstash Redis databases. ```hcl example.tf resource "upstash_redis_database" "exampleDB" { database_name = "Terraform DB6" region = "eu-west-1" tls = "true" multizone = "true" } ``` ## Schema ### Required Name of the database Region of the database. Possible values are: `global`, `eu-west-1`, `us-east-1`, `us-west-1`, `ap-northeast-1` , `eu-central1` ### Optional Upgrade to higher plans automatically when it hits quotas Enable eviction, to evict keys when your database reaches the max size Primary region for the database (Only works if region='global'. Can be one of \[us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2]) Read regions for the database (Only works if region='global' and primary\_region is set. Can be any combination of \[us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2], excluding the one given as primary.) When enabled, data is encrypted in transit. (If changed to false from true, results in deletion and recreation of the resource) ### Read-Only Creation time of the database Unique Database ID for created database Type of the database Daily bandwidth limit for the database Disk threshold for the database Max clients for the database Max commands per second for the database Max entry size for the database Max request size for the database Memory threshold for the database Database URL for connection The ID of this resource. Password of the database Port of the endpoint Rest Token for the database. Rest Token for the database. State of the database User email for the database # upstash_team Source: https://upstash.com/docs/devops/terraform/resources/upstash_team Create and manage teams on Upstash. ```hcl example.tf resource "upstash_team" "exampleTeam" { team_name = "TerraformTeam" copy_cc = false team_members = { # Owner is the owner of the api_key. "X@Y.Z": "owner", "A@B.C": "dev", "E@E.F": "finance", } } ``` ## Schema ### Required Whether Credit Card is copied Members of the team. (Owner must be specified, which is the owner of the api key.) Name of the team ### Read-Only The ID of this resource. Unique Cluster ID for created cluster # Get Started Source: https://upstash.com/docs/introduction Create a Redis Database within seconds Create a Vector Database for AI & LLMs Publish your first message Write durable serverless functions ## Concepts Upstash is serverless. You don't need to provision any infrastructure. Just create a database and start using it. Price scales to zero. You don't pay for idle or unused resources. You pay only for what you use. Upstash Redis replicates your data for the best latency all over the world. Upstash REST APIs enable access from all types of runtimes. ## Get In touch Follow us on X for the latest news and updates. Join our Discord Community and ask your questions to the team and other developers. Raise an issue on GitHub. # API Rate Limit Response Source: https://upstash.com/docs/qstash/api/api-ratelimiting This page documents the rate limiting behavior of our API and explains how to handle different types of rate limit errors. ## Overview Our API implements rate limiting to ensure fair usage and maintain service stability. There are three types of rate limits: 1. **Daily rate limit** 2. **Burst rate limit** 3. **Chat-based rate limit** When a rate limit is exceeded, the API returns a 429 status code along with specific headers that provide information about the limit, remaining requests/tokens, and reset time. You can learn more about QStash plans and their limits on the [QStash pricing page](https://upstash.com/pricing/qstash). ### Daily Rate Limit This is a **daily** limit applied to publish-related API endpoints (new message requests like publish, enqueue, or batch). Other API requests, such as fetching logs or messages, do not count toward this limit. **Headers**: * `RateLimit-Limit`: Maximum number of requests allowed per day * `RateLimit-Remaining`: Remaining number of requests for the day * `RateLimit-Reset`: Time (in unix timestamp) when the daily limit will reset ### Burst Rate Limit This is a short-term limit **per second** to prevent rapid bursts of requests. This limit applies to all API endpoints. **Headers**: * `Burst-RateLimit-Limit`: Maximum number of requests allowed in the burst window (1 second) * `Burst-RateLimit-Remaining`: Remaining number of requests in the burst window (1 second) * `Burst-RateLimit-Reset`: Time (in unix timestamp) when the burst limit will reset ### Chat-based Rate Limit This limit is applied to chat-related API endpoints. **Headers**: * `x-ratelimit-limit-requests`: Maximum number of requests allowed per day * `x-ratelimit-limit-tokens`: Maximum number of tokens allowed per day * `x-ratelimit-remaining-requests`: Remaining number of requests for the day * `x-ratelimit-remaining-tokens`: Remaining number of tokens for the day * `x-ratelimit-reset-requests`: Time (in unix timestamp) until the request limit resets * `x-ratelimit-reset-tokens`: Time (in unix timestamp) when the token limit will reset ### Example Rate Limit Error Handling ```typescript Handling Daily Rate Limit Error import { QstashDailyRatelimitError } from "@upstash/qstash"; try { // Example of a publish request that could hit the daily rate limit const result = await client.publishJSON({ url: "https://my-api...", // or urlGroup: "the name or id of a url group" body: { hello: "world", }, }); } catch (error) { if (error instanceof QstashDailyRatelimitError) { console.log("Daily rate limit exceeded. Retry after:", error.reset); // Implement retry logic or notify the user } else { console.error("An unexpected error occurred:", error); } } ``` ```typescript Handling Burst Rate Limit Error import { QstashRatelimitError } from "@upstash/qstash"; try { // Example of a request that could hit the burst rate limit const result = await client.publishJSON({ url: "https://my-api...", // or urlGroup: "the name or id of a url group" body: { hello: "world", }, }); } catch (error) { if (error instanceof QstashRatelimitError) { console.log("Burst rate limit exceeded. Retry after:", error.reset); // Implement exponential backoff or delay before retrying } else { console.error("An unexpected error occurred:", error); } } ``` ```typescript Handling Chat-based Rate Limit Error import { QstashChatRatelimitError, Client, openai } from "@upstash/qstash"; try { // Example of a chat-related request that could hit the chat rate limit const client = new Client({ token: "", }); const result = await client.publishJSON({ api: { name: "llm", provider: openai({ token: process.env.OPENAI_API_KEY! }), }, body: { model: "gpt-3.5-turbo", messages: [ { role: "user", content: "Where is the capital of Turkey?", }, ], }, callback: "https://oz.requestcatcher.com/", }); } catch (error) { if (error instanceof QstashChatRatelimitError) { console.log("Chat rate limit exceeded. Retry after:", error.resetRequests); // Handle chat-specific rate limiting, perhaps by queueing requests } else { console.error("An unexpected error occurred:", error); } } ``` # Authentication Source: https://upstash.com/docs/qstash/api/authentication Authentication for the QStash API You'll need to authenticate your requests to access any of the endpoints in the QStash API. In this guide, we'll look at how authentication works. ## Bearer Token When making requests to QStash, you will need your `QSTASH_TOKEN` — you will find it in the [console](https://console.upstash.com/qstash). Here's how to add the token to the request header using cURL: ```bash curl https://qstash.upstash.io/v2/publish/... \ -H "Authorization: Bearer " ``` ## Query Parameter In environments where setting the header is not possible, you can use the `qstash_token` query parameter instead. ```bash curl https://qstash.upstash.io/v2/publish/...?qstash_token= ``` Always keep your token safe and reset it if you suspect it has been compromised. # Delete a message from the DLQ Source: https://upstash.com/docs/qstash/api/dlq/deleteMessage DELETE https://qstash.upstash.io/v2/dlq/{dlqId} Manually remove a message Delete a message from the DLQ. ## Request The dlq id of the message you want to remove. You will see this id when listing all messages in the dlq with the [/v2/dlq](/qstash/api/dlq/listMessages) endpoint. ## Response The endpoint doesn't return anything, a status code of 200 means the message is removed from the DLQ. If the message is not found in the DLQ, (either is has been removed by you, or automatically), the endpoint returns a 404 status code. ```sh curl -X DELETE https://qstash.upstash.io/v2/dlq/my-dlq-id \ -H "Authorization: Bearer " ``` # Delete multiple messages from the DLQ Source: https://upstash.com/docs/qstash/api/dlq/deleteMessages DELETE https://qstash.upstash.io/v2/dlq Manually remove messages Delete multiple messages from the DLQ. You can get the `dlqId` from the [list DLQs endpoint](/qstash/api/dlq/listMessages). ## Request The list of DLQ message IDs to remove. ## Response A deleted object with the number of deleted messages. ```JSON { "deleted": number } ``` ```json 200 OK { "deleted": 3 } ``` ```sh curl curl -XDELETE https://qstash.upstash.io/v2/dlq \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "dlqIds": ["11111-0", "22222-0", "33333-0"] }' ``` ```js Node const response = await fetch("https://qstash.upstash.io/v2/dlq", { method: "DELETE", headers: { Authorization: "Bearer ", "Content-Type": "application/json", }, body: { dlqIds: [ "11111-0", "22222-0", "33333-0", ], }, }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', } data = { "dlqIds": [ "11111-0", "22222-0", "33333-0" ] } response = requests.delete( 'https://qstash.upstash.io/v2/dlq', headers=headers, data=data ) ``` ```go Go var data = strings.NewReader(`{ "dlqIds": [ "11111-0", "22222-0", "33333-0" ] }`) req, err := http.NewRequest("DELETE", "https://qstash.upstash.io/v2/dlq", data) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` # Get a message from the DLQ Source: https://upstash.com/docs/qstash/api/dlq/getMessage GET https://qstash.upstash.io/v2/dlq/{dlqId} Get a message from the DLQ Get a message from DLQ. ## Request The dlq id of the message you want to retrieve. You will see this id when listing all messages in the dlq with the [/v2/dlq](/qstash/api/dlq/listMessages) endpoint, as well as in the content of [the failure callback](https://docs.upstash.com/qstash/features/callbacks#what-is-a-failure-callback) ## Response If the message is not found in the DLQ, (either is has been removed by you, or automatically), the endpoint returns a 404 status code. ```sh curl -X GET https://qstash.upstash.io/v2/dlq/my-dlq-id \ -H "Authorization: Bearer " ``` # List messages in the DLQ Source: https://upstash.com/docs/qstash/api/dlq/listMessages GET https://qstash.upstash.io/v2/dlq List and paginate through all messages currently inside the DLQ List all messages currently inside the DLQ ## Request By providing a cursor you can paginate through all of the messages in the DLQ Filter DLQ messages by message id. Filter DLQ messages by url. Filter DLQ messages by url group. Filter DLQ messages by schedule id. Filter DLQ messages by queue name. Filter DLQ messages by API name. Filter DLQ messages by starting date, in milliseconds (Unix timestamp). This is inclusive. Filter DLQ messages by ending date, in milliseconds (Unix timestamp). This is inclusive. Filter DLQ messages by HTTP response status code. Filter DLQ messages by IP address of the publisher. The number of messages to return. Default and maximum is 100. The sorting order of DLQ messages by timestamp. Valid values are "earliestFirst" and "latestFirst". The default is "earliestFirst". ## Response A cursor which you can use in subsequent requests to paginate through all messages. If no cursor is returned, you have reached the end of the messages. ```sh curl https://qstash.upstash.io/v2/dlq \ -H "Authorization: Bearer " ``` ```sh with cursor curl https://qstash.upstash.io/v2/dlq?cursor=xxx \ -H "Authorization: Bearer " ``` ```json 200 OK { "messages": [ { "messageId": "msg_123", "topicId": "tpc_123", "url":"https://example.com", "method": "POST", "header": { "My-Header": ["my-value"] }, "body": "{\"foo\":\"bar\"}", "createdAt": 1620000000000, "state": "failed" } ] } ``` # Enqueue a Message Source: https://upstash.com/docs/qstash/api/enqueue POST https://qstash.upstash.io/v2/enqueue/{queueName}/{destination} Enqueue a message ## Request The name of the queue that message will be enqueued on. If doesn't exist, it will be created automatically. Destination can either be a topic name or id that you configured in the Upstash console, a valid url where the message gets sent to, or a valid QStash API name like `api/llm`. If the destination is a URL, make sure the URL is prefixed with a valid protocol (`http://` or `https://`) Id to use while deduplicating messages, so that only one message with the given deduplication id is published. When set to true, automatically deduplicates messages based on their content, so that only one message with the same content is published. Content based deduplication creates unique deduplication ids based on the following message fields: * Destination * Body * Headers ## Response ```sh curl curl -X POST "https://qstash.upstash.io/v2/enqueue/myQueue/https://www.example.com" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Upstash-Method: POST" \ -H "Upstash-Retries: 3" \ -H "Upstash-Forward-Custom-Header: custom-value" \ -d '{"message":"Hello, World!"}' ``` ```js Node const response = await fetch( "https://qstash.upstash.io/v2/enqueue/myQueue/https://www.example.com", { method: "POST", headers: { Authorization: "Bearer ", "Content-Type": "application/json", "Upstash-Method": "POST", "Upstash-Retries": "3", "Upstash-Forward-Custom-Header": "custom-value", }, body: JSON.stringify({ message: "Hello, World!", }), } ); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', 'Upstash-Method': 'POST', 'Upstash-Retries': '3', 'Upstash-Forward-Custom-Header': 'custom-value', } json_data = { 'message': 'Hello, World!', } response = requests.post( 'https://qstash.upstash.io/v2/enqueue/myQueue/https://www.example.com', headers=headers, json=json_data ) ``` ```go Go var data = strings.NewReader(`{"message":"Hello, World!"}`) req, err := http.NewRequest("POST", "https://qstash.upstash.io/v2/enqueue/myQueue/https://www.example.com", data) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Content-Type", "application/json") req.Header.Set("Upstash-Method", "POST") req.Header.Set("Upstash-Retries", "3") req.Header.Set("Upstash-Forward-Custom-Header", "custom-value") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json URL { "messageId": "msd_1234", "url": "https://www.example.com" } ``` ```json URL Group [ { "messageId": "msd_1234", "url": "https://www.example.com" }, { "messageId": "msd_5678", "url": "https://www.somewhere-else.com", "deduplicated": true } ] ``` # List Events Source: https://upstash.com/docs/qstash/api/events/list GET https://qstash.upstash.io/v2/events List all events that happened, such as message creation or delivery QStash events are being renamed to [Logs](/qstash/api/logs/list) to better reflect their purpose and to not get confused with [Workflow Events](/workflow/howto/events). ## Request By providing a cursor you can paginate through all of the events. Filter events by message id. Filter events by [state](/qstash/howto/debug-logs) | Value | Description | | ------------------ | ---------------------------------------------------------------------------------------- | | `CREATED` | The message has been accepted and stored in QStash | | `ACTIVE` | The task is currently being processed by a worker. | | `RETRY` | The task has been scheduled to retry. | | `ERROR` | The execution threw an error and the task is waiting to be retried or failed. | | `IN_PROGRESS` | The task is in one of `ACTIVE`, `RETRY` or `ERROR` state. | | `DELIVERED` | The message was successfully delivered. | | `FAILED` | The task has errored too many times or encountered an error that it cannot recover from. | | `CANCEL_REQUESTED` | The cancel request from the user is recorded. | | `CANCELLED` | The cancel request from the user is honored. | Filter events by url. Filter events by URL Group (topic) name. Filter events by schedule id. Filter events by queue name. Filter events by starting date, in milliseconds (Unix timestamp). This is inclusive. Filter events by ending date, in milliseconds (Unix timestamp). This is inclusive. The number of events to return. Default and max is 1000. The sorting order of events by timestamp. Valid values are "earliestFirst" and "latestFirst". The default is "latestFirst". ## Response A cursor which you can use in subsequent requests to paginate through all events. If no cursor is returned, you have reached the end of the events. Timestamp of this log entry, in milliseconds The associated message id The headers of the message. Base64 encoded body of the message. The current state of the message at this point in time. | Value | Description | | ------------------ | ---------------------------------------------------------------------------------------- | | `CREATED` | The message has been accepted and stored in QStash | | `ACTIVE` | The task is currently being processed by a worker. | | `RETRY` | The task has been scheduled to retry. | | `ERROR` | The execution threw an error and the task is waiting to be retried or failed. | | `DELIVERED` | The message was successfully delivered. | | `FAILED` | The task has errored too many times or encountered an error that it cannot recover from. | | `CANCEL_REQUESTED` | The cancel request from the user is recorded. | | `CANCELLED` | The cancel request from the user is honored. | An explanation what went wrong The next scheduled time of the message. (Unix timestamp in milliseconds) The destination url The name of the URL Group (topic) if this message was sent through a topic The name of the endpoint if this message was sent through a URL Group The scheduleId of the message if the message is triggered by a schedule The name of the queue if this message is enqueued on a queue The headers that are forwarded to the users endpoint Base64 encoded body of the message The status code of the response. Only set if the state is `ERROR` The base64 encoded body of the response. Only set if the state is `ERROR` The headers of the response. Only set if the state is `ERROR` The timeout(in milliseconds) of the outgoing http requests, after which Qstash cancels the request Method is the HTTP method of the message for outgoing request Callback is the URL address where QStash sends the response of a publish The headers that are passed to the callback url Failure Callback is the URL address where QStash sends the response of a publish The headers that are passed to the failure callback url The number of retries that should be attempted in case of delivery failure ```sh curl curl https://qstash.upstash.io/v2/events \ -H "Authorization: Bearer " ``` ```javascript Node const response = await fetch("https://qstash.upstash.io/v2/events", { headers: { Authorization: "Bearer ", }, }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/events', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/events", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "cursor": "1686652644442-12", "events":[ { "time": "1686652644442", "messageId": "msg_123", "state": "delivered", "url": "https://example.com", "header": { "Content-Type": [ "application/x-www-form-urlencoded" ] }, "body": "bWVyaGFiYSBiZW5pbSBhZGltIHNhbmNhcg==" } ] } ``` # Get Flow-Control Keys Source: https://upstash.com/docs/qstash/api/flow-control/get GET https://qstash.upstash.io/v2/flowControl/{flowControlKey} Get Information on Flow-Control ## Request The key of the flow control. See the [flow control](/qstash/features/flowcontrol) for more details. ## Response The key of of the flow control. The number of messages in the wait list that waits for `parallelism` set in the flow control. ```sh curl -X GET https://qstash.upstash.io/v2/flowControl/YOUR_FLOW_CONTROL_KEY -H "Authorization: Bearer " ``` # List Flow-Control Keys Source: https://upstash.com/docs/qstash/api/flow-control/list GET https://qstash.upstash.io/v2/flowControl/ List all Flow Control keys ## Response The key of the flow control. See the [flow control](/qstash/features/flowcontrol) for more details. The number of messages in the wait list that waits for `parallelism` set in the flow control. ```sh curl -X GET https://qstash.upstash.io/v2/flowControl/ -H "Authorization: Bearer " ``` # Create Chat Completion Source: https://upstash.com/docs/qstash/api/llm/create POST https://qstash.upstash.io/llm/v1/chat/completions Creates a chat completion of one or more messages Creates a chat completion that generates a textual response for one or more messages using a large language model. ## Request Name of the model. One or more chat messages. The role of the message author. One of `system`, `assistant`, or `user`. The content of the message. An optional name for the participant. Provides the model information to differentiate between participants of the same role. Number between `-2.0` and `2.0`. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. Modify the likelihood of specified tokens appearing in the completion. Accepts a JSON object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from `-100` to `100`. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between `-1` and `1` should decrease or increase likelihood of selection; values like `-100` or `100` should result in a ban or exclusive selection of the relevant token. Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the content of message. An integer between `0` and `20` specifying the number of most likely tokens to return at each token position, each with an associated log probability. logprobs must be set to true if this parameter is used. The maximum number of tokens that can be generated in the chat completion. How many chat completion choices to generate for each input message. Note that you will be charged based on the number of generated tokens across all of the choices. Keep `n` as `1` to minimize costs. Number between `-2.0` and `2.0`. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. An object specifying the format that the model must output. Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the message the model generates is valid JSON. **Important**: when using JSON mode, you must also instruct the model to produce JSON yourself via a system or user message. Without this, the model may generate an unending stream of whitespace until the generation reaches the token limit, resulting in a long-running and seemingly "stuck" request. Also note that the message content may be partially cut off if `finish_reason="length"`, which indicates the generation exceeded max\_tokens or the conversation exceeded the max context length. Must be one of `text` or `json_object`. This feature is in Beta. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. Up to 4 sequences where the API will stop generating further tokens. If set, partial message deltas will be sent. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a `data: [DONE]` message. What sampling temperature to use, between `0` and `2`. Higher values like `0.8` will make the output more random, while lower values like `0.2` will make it more focused and deterministic. We generally recommend altering this or `top_p` but not both. An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with `top_p` probability mass. So `0.1` means only the tokens comprising the top \`10%\`\` probability mass are considered. We generally recommend altering this or `temperature` but not both. ## Response Returned when `stream` is `false` or not set. A unique identifier for the chat completion. A list of chat completion choices. Can be more than one if `n` is greater than `1`. A chat completion message generated by the model. The role of the author of this message. The contents of the message. The reason the model stopped generating tokens. This will be `stop` if the model hit a natural stop point or a provided stop sequence, `length` if the maximum number of tokens specified in the request was reached. The stop string or token id that caused the completion to stop, null if the completion finished for some other reason including encountering the EOS token The index of the choice in the list of choices. Log probability information for the choice. A list of message content tokens with log probability information. The token. The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely. A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token. List of the most likely tokens and their log probability, at this token position. In rare cases, there may be fewer than the number of requested `top_logprobs` returned. The token. The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely. A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token. The Unix timestamp (in seconds) of when the chat completion was created. The model used for the chat completion. This fingerprint represents the backend configuration that the model runs with. Can be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism. The object type, which is always `chat.completion`. Usage statistics for the completion request. Number of tokens in the generated completion. Number of tokens in the prompt. Total number of tokens used in the request (prompt + completion). ## Stream Response Returned when `stream` is `true`. A unique identifier for the chat completion. Each chunk has the same ID. A list of chat completion choices. Can be more than one if `n` is greater than `1`. Can also be empty for the last chunk. A chat completion delta generated by streamed model responses. The role of the author of this message. The contents of the chunk message. The reason the model stopped generating tokens. This will be `stop` if the model hit a natural stop point or a provided stop sequence, `length` if the maximum number of tokens specified in the request was reached. The index of the choice in the list of choices. Log probability information for the choice. A list of message content tokens with log probability information. The token. The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely. A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token. List of the most likely tokens and their log probability, at this token position. In rare cases, there may be fewer than the number of requested `top_logprobs` returned. The token. The log probability of this token, if it is within the top 20 most likely tokens. Otherwise, the value `-9999.0` is used to signify that the token is very unlikely. A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token. The Unix timestamp (in seconds) of when the chat completion was created. Each chunk has the same timestamp. The model used for the chat completion. This fingerprint represents the backend configuration that the model runs with. Can be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism. The object type, which is always `chat.completion.chunk`. it contains a null value except for the last chunk which contains the token usage statistics for the entire request. Number of tokens in the generated completion. Number of tokens in the prompt. Total number of tokens used in the request (prompt + completion). ```sh curl curl "https://qstash.upstash.io/llm/v1/chat/completions" \ -X POST \ -H "Authorization: Bearer QSTASH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "meta-llama/Meta-Llama-3-8B-Instruct", "messages": [ { "role": "user", "content": "What is the capital of Turkey?" } ] }' ``` ```json 200 OK { "id": "cmpl-abefcf66fae945b384e334e36c7fdc97", "object": "chat.completion", "created": 1717483987, "model": "meta-llama/Meta-Llama-3-8B-Instruct", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "The capital of Turkey is Ankara." }, "logprobs": null, "finish_reason": "stop", "stop_reason": null } ], "usage": { "prompt_tokens": 18, "total_tokens": 26, "completion_tokens": 8 } } ``` ```json 200 OK - Stream data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":" capital"},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":" of"},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":" Turkey"},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":" Ankara"},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}]} data: {"id":"cmpl-dfc1ad80d0254c2aaf3e7775d1830c9d","object":"chat.completion.chunk","created":1717484084,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"delta":{"content":""},"finish_reason":"stop"}],"usage":{"prompt_tokens":18,"total_tokens":26,"completion_tokens":8}} data: [DONE] ``` # List Logs Source: https://upstash.com/docs/qstash/api/logs/list GET https://qstash.upstash.io/v2/logs Paginate through logs of published messages ## Request By providing a cursor you can paginate through all of the logs. Filter logs by message id. Filter logs by [state](/qstash/howto/debug-logs) | Value | Description | | ------------------ | ---------------------------------------------------------------------------------------- | | `CREATED` | The message has been accepted and stored in QStash | | `ACTIVE` | The task is currently being processed by a worker. | | `RETRY` | The task has been scheduled to retry. | | `ERROR` | The execution threw an error and the task is waiting to be retried or failed. | | `IN_PROGRESS` | The task is in one of `ACTIVE`, `RETRY` or `ERROR` state. | | `DELIVERED` | The message was successfully delivered. | | `FAILED` | The task has errored too many times or encountered an error that it cannot recover from. | | `CANCEL_REQUESTED` | The cancel request from the user is recorded. | | `CANCELLED` | The cancel request from the user is honored. | Filter logs by url. Filter logs by URL Group (topic) name. Filter logs by schedule id. Filter logs by queue name. Filter logs by starting date, in milliseconds (Unix timestamp). This is inclusive. Filter logs by ending date, in milliseconds (Unix timestamp). This is inclusive. The number of logs to return. Default and max is 1000. The sorting order of logs by timestamp. Valid values are "earliestFirst" and "latestFirst". The default is "latestFirst". ## Response A cursor which you can use in subsequent requests to paginate through all logs. If no cursor is returned, you have reached the end of the logs. Timestamp of this log entry, in milliseconds The associated message id The headers of the message. Base64 encoded body of the message. The current state of the message at this point in time. | Value | Description | | ------------------ | ---------------------------------------------------------------------------------------- | | `CREATED` | The message has been accepted and stored in QStash | | `ACTIVE` | The task is currently being processed by a worker. | | `RETRY` | The task has been scheduled to retry. | | `ERROR` | The execution threw an error and the task is waiting to be retried or failed. | | `DELIVERED` | The message was successfully delivered. | | `FAILED` | The task has errored too many times or encountered an error that it cannot recover from. | | `CANCEL_REQUESTED` | The cancel request from the user is recorded. | | `CANCELLED` | The cancel request from the user is honored. | An explanation what went wrong The next scheduled time of the message. (Unix timestamp in milliseconds) The destination url The name of the URL Group (topic) if this message was sent through a topic The name of the endpoint if this message was sent through a URL Group The scheduleId of the message if the message is triggered by a schedule The name of the queue if this message is enqueued on a queue The headers that are forwarded to the users endpoint Base64 encoded body of the message The status code of the response. Only set if the state is `ERROR` The base64 encoded body of the response. Only set if the state is `ERROR` The headers of the response. Only set if the state is `ERROR` The timeout(in milliseconds) of the outgoing http requests, after which Qstash cancels the request Method is the HTTP method of the message for outgoing request Callback is the URL address where QStash sends the response of a publish The headers that are passed to the callback url Failure Callback is the URL address where QStash sends the response of a publish The headers that are passed to the failure callback url The number of retries that should be attempted in case of delivery failure ```sh curl curl https://qstash.upstash.io/v2/logs \ -H "Authorization: Bearer " ``` ```javascript Node const response = await fetch("https://qstash.upstash.io/v2/logs", { headers: { Authorization: "Bearer ", }, }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/logs', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/logs", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "cursor": "1686652644442-12", "events":[ { "time": "1686652644442", "messageId": "msg_123", "state": "delivered", "url": "https://example.com", "header": { "Content-Type": [ "application/x-www-form-urlencoded" ] }, "body": "bWVyaGFiYSBiZW5pbSBhZGltIHNhbmNhcg==" } ] } ``` # Batch Messages Source: https://upstash.com/docs/qstash/api/messages/batch POST https://qstash.upstash.io/v2/batch Send multiple messages in a single request You can learn more about batching in the [batching section](/qstash/features/batch). API playground is not available for this endpoint. You can use the cURL example below. You can publish to destination, URL Group or queue in the same batch request. ## Request The endpoint is `POST https://qstash.upstash.io/v2/batch` and the body is an array of messages. Each message has the following fields: ``` destination: string headers: headers object body: string ``` The headers are identical to the headers in the [create](/qstash/api/publish#request) endpoint. ```shell cURL curl -XPOST https://qstash.upstash.io/v2/batch -H "Authorization: Bearer XXX" \ -H "Content-Type: application/json" \ -d ' [ { "destination": "myUrlGroup", "headers":{ "Upstash-Delay":"5s", "Upstash-Forward-Hello":"123456" }, "body": "Hello World" }, { "queue": "test", "destination": "https://example.com/destination", "headers":{ "Upstash-Forward-Hello":"789" } }, { "destination": "https://example.com/destination1", "headers":{ "Upstash-Delay":"7s", "Upstash-Forward-Hello":"789" } }, { "destination": "https://example.com/destination2", "headers":{ "Upstash-Delay":"9s", "Upstash-Forward-Hello":"again" } } ]' ``` ## Response ```json [ [ { "messageId": "msg_...", "url": "https://myUrlGroup-endpoint1.com" }, { "messageId": "msg_...", "url": "https://myUrlGroup-endpoint2.com" } ], { "messageId": "msg_...", }, { "messageId": "msg_..." }, { "messageId": "msg_..." } ] ``` # Bulk Cancel Messages Source: https://upstash.com/docs/qstash/api/messages/bulk-cancel DELETE https://qstash.upstash.io/v2/messages Stop delivery of multiple messages at once Bulk cancel allows you to cancel multiple messages at once. Cancelling a message will remove it from QStash and stop it from being delivered in the future. If a message is in flight to your API, it might be too late to cancel. If you provide a set of message IDs in the body of the request, only those messages will be cancelled. If you include filter parameters in the request body, only the messages that match the filters will be canceled. If the `messageIds` array is empty, QStash will cancel all of your messages. If no body is sent, QStash will also cancel all of your messages. This operation scans all your messages and attempts to cancel them. If an individual message cannot be cancelled, it will not continue and will return an error message. Therefore, some messages may not be cancelled at the end. In such cases, you can run the bulk cancel operation multiple times. You can filter the messages to cancel by including filter parameters in the request body. ## Request The list of message IDs to cancel. Filter messages to cancel by queue name. Filter messages to cancel by destination URL. Filter messages to cancel by URL Group (topic) name. Filter messages to cancel by starting date, in milliseconds (Unix timestamp). This is inclusive. Filter messages to cancel by ending date, specified in milliseconds (Unix timestamp). This is inclusive. Filter messages to cancel by schedule ID. Filter messages to cancel by IP address of publisher. ## Response A cancelled object with the number of cancelled messages. ```JSON { "cancelled": number } ``` ```sh curl curl -XDELETE https://qstash.upstash.io/v2/messages/ \ -H "Content-Type: application/json" \ -H "Authorization: Bearer " \ -d '{"messageIds": ["msg_id_1", "msg_id_2", "msg_id_3"]}' ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/messages', { method: 'DELETE', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', body: { messageIds: [ "msg_id_1", "msg_id_2", "msg_id_3", ], }, } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', } data = { "messageIds": [ "msg_id_1", "msg_id_2", "msg_id_3" ] } response = requests.delete( 'https://qstash.upstash.io/v2/messages', headers=headers, data=data ) ``` ```go Go var data = strings.NewReader(`{ "messageIds": [ "msg_id_1", "msg_id_2", "msg_id_3" ] }`) req, err := http.NewRequest("DELETE", "https://qstash.upstash.io/v2/messages", data) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 202 Accepted { "cancelled": 10 } ``` # Cancel Message Source: https://upstash.com/docs/qstash/api/messages/cancel DELETE https://qstash.upstash.io/v2/messages/{messageId} Stop delivery of an existing message Cancelling a message will remove it from QStash and stop it from being delivered in the future. If a message is in flight to your API, it might be too late to cancel. ## Request The id of the message to cancel. ## Response This endpoint only returns `202 OK` ```sh curl curl -XDELETE https://qstash.upstash.io/v2/messages/msg_123 \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/messages/msg_123', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.delete( 'https://qstash.upstash.io/v2/messages/msg_123', headers=headers ) ``` ```go Go req, err := http.NewRequest("DELETE", "https://qstash.upstash.io/v2/messages/msg_123", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```text 202 Accepted OK ``` # Get Message Source: https://upstash.com/docs/qstash/api/messages/get GET https://qstash.upstash.io/v2/messages/{messageId} Retrieve a message by its id ## Request The id of the message to retrieve. Messages are removed from the database shortly after they're delivered, so you will not be able to retrieve a message after. This endpoint is intended to be used for accessing messages that are in the process of being delivered/retried. ## Response ```sh curl curl https://qstash.upstash.io/v2/messages/msg_123 \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch("https://qstash.upstash.io/v2/messages/msg_123", { headers: { Authorization: "Bearer ", }, }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/messages/msg_123', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/messages/msg_123", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "messageId": "msg_123", "topicName": "myTopic", "url":"https://example.com", "method": "POST", "header": { "My-Header": ["my-value"] }, "body": "{\"foo\":\"bar\"}", "createdAt": 1620000000000 } ``` # Publish a Message Source: https://upstash.com/docs/qstash/api/publish POST https://qstash.upstash.io/v2/publish/{destination} Publish a message ## Request Destination can either be a topic name or id that you configured in the Upstash console, a valid url where the message gets sent to, or a valid QStash API name like `api/llm`. If the destination is a URL, make sure the URL is prefixed with a valid protocol (`http://` or `https://`) Delay the message delivery. Format for this header is a number followed by duration abbreviation, like `10s`. Available durations are `s` (seconds), `m` (minutes), `h` (hours), `d` (days). example: "50s" | "3m" | "10h" | "1d" Delay the message delivery until a certain time in the future. The format is a unix timestamp in seconds, based on the UTC timezone. When both `Upstash-Not-Before` and `Upstash-Delay` headers are provided, `Upstash-Not-Before` will be used. Id to use while deduplicating messages, so that only one message with the given deduplication id is published. When set to true, automatically deduplicates messages based on their content, so that only one message with the same content is published. Content based deduplication creates unique deduplication ids based on the following message fields: * Destination * Body * Headers ## Response ```sh curl curl -X POST "https://qstash.upstash.io/v2/publish/https://www.example.com" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Upstash-Method: POST" \ -H "Upstash-Delay: 10s" \ -H "Upstash-Retries: 3" \ -H "Upstash-Forward-Custom-Header: custom-value" \ -d '{"message":"Hello, World!"}' ``` ```js Node const response = await fetch( "https://qstash.upstash.io/v2/publish/https://www.example.com", { method: "POST", headers: { Authorization: "Bearer ", "Content-Type": "application/json", "Upstash-Method": "POST", "Upstash-Delay": "10s", "Upstash-Retries": "3", "Upstash-Forward-Custom-Header": "custom-value", }, body: JSON.stringify({ message: "Hello, World!", }), } ); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', 'Upstash-Method': 'POST', 'Upstash-Delay': '10s', 'Upstash-Retries': '3', 'Upstash-Forward-Custom-Header': 'custom-value', } json_data = { 'message': 'Hello, World!', } response = requests.post( 'https://qstash.upstash.io/v2/publish/https://www.example.com', headers=headers, json=json_data ) ``` ```go Go var data = strings.NewReader(`{"message":"Hello, World!"}`) req, err := http.NewRequest("POST", "https://qstash.upstash.io/v2/publish/https://www.example.com", data) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Content-Type", "application/json") req.Header.Set("Upstash-Method", "POST") req.Header.Set("Upstash-Delay", "10s") req.Header.Set("Upstash-Retries", "3") req.Header.Set("Upstash-Forward-Custom-Header", "custom-value") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json URL { "messageId": "msd_1234", "url": "https://www.example.com" } ``` ```json URL Group [ { "messageId": "msd_1234", "url": "https://www.example.com" }, { "messageId": "msd_5678", "url": "https://www.somewhere-else.com", "deduplicated": true } ] ``` # Get a Queue Source: https://upstash.com/docs/qstash/api/queues/get GET https://qstash.upstash.io/v2/queues/{queueName} Retrieves a queue ## Request The name of the queue to retrieve. ## Response The creation time of the queue. UnixMilli The update time of the queue. UnixMilli The name of the queue. The number of parallel consumers consuming from [the queue](/qstash/features/queues). The number of unprocessed messages that exist in [the queue](/qstash/features/queues). ```sh curl curl https://qstash.upstash.io/v2/queues/my-queue \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/queue/my-queue', { headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/queue/my-queue', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/queue/my-queue", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "createdAt": 1623345678001, "updatedAt": 1623345678001, "name": "my-queue", "parallelism" : 5, "lag" : 100 } ``` # List Queues Source: https://upstash.com/docs/qstash/api/queues/list GET https://qstash.upstash.io/v2/queues List all your queues ## Request No parameters ## Response The creation time of the queue. UnixMilli The update time of the queue. UnixMilli The name of the queue. The number of parallel consumers consuming from [the queue](/qstash/features/queues). The number of unprocessed messages that exist in [the queue](/qstash/features/queues). ```sh curl curl https://qstash.upstash.io/v2/queues \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch("https://qstash.upstash.io/v2/queues", { headers: { Authorization: "Bearer ", }, }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/queues', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/queues", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK [ { "createdAt": 1623345678001, "updatedAt": 1623345678001, "name": "my-queue", "parallelism" : 5, "lag" : 100 }, // ... ] ``` # Pause Queue Source: https://upstash.com/docs/qstash/api/queues/pause POST https://qstash.upstash.io/v2/queues/{queueName}/pause Pause an active queue Pausing a queue stops the delivery of enqueued messages. The queue will still accept new messages, but they will wait until the queue becomes active for delivery. If the queue is already paused, this action has no effect. Resuming or creating a queue may take up to a minute. Therefore, it is not recommended to pause or delete a queue during critical operations. ## Request The name of the queue to pause. ## Response This endpoint simply returns 200 OK if the queue is paused successfully. ```sh curl curl -X POST https://qstash.upstash.io/v2/queues/queue_1234/pause \ -H "Authorization: Bearer " ``` ```js Node import { Client } from "@upstash/qstash"; /** * Import a fetch polyfill only if you are using node prior to v18. * This is not necessary for nextjs, deno or cloudflare workers. */ import "isomorphic-fetch"; const c = new Client({ token: "", }); c.queue({ queueName: "" }).pause() ``` ```python Python from qstash import QStash client = QStash("") client.queue.pause("") ``` ```go Go package main import ( "github.com/upstash/qstash-go" ) func main() { client := qstash.NewClient("") // error checking is omitted for brevity err := client.Queues().Pause("") } ``` # Remove a Queue Source: https://upstash.com/docs/qstash/api/queues/remove DELETE https://qstash.upstash.io/v2/queues/{queueName} Removes a queue Resuming or creating a queue may take up to a minute. Therefore, it is not recommended to pause or delete a queue during critical operations. ## Request The name of the queue to remove. ## Response This endpoint returns 200 if the queue is removed successfully, or it doesn't exist. ```sh curl curl https://qstash.upstash.io/v2/queues/my-queue \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/queue/my-queue', { method: "DELETE", headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.delete( 'https://qstash.upstash.io/v2/queue/my-queue', headers=headers ) ``` ```go Go req, err := http.NewRequest("DELETE", "https://qstash.upstash.io/v2/queue/my-queue", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` # Resume Queue Source: https://upstash.com/docs/qstash/api/queues/resume POST https://qstash.upstash.io/v2/queues/{queueName}/resume Resume a paused queue Resuming a queue starts the delivery of enqueued messages from the earliest undelivered message. If the queue is already active, this action has no effect. ## Request The name of the queue to resume. ## Response This endpoint simply returns 200 OK if the queue is resumed successfully. ```sh curl curl -X POST https://qstash.upstash.io/v2/queues/queue_1234/resume \ -H "Authorization: Bearer " ``` ```js Node import { Client } from "@upstash/qstash"; /** * Import a fetch polyfill only if you are using node prior to v18. * This is not necessary for nextjs, deno or cloudflare workers. */ import "isomorphic-fetch"; const c = new Client({ token: "", }); c.queue({ queueName: "" }).resume() ``` ```python Python from qstash import QStash client = QStash("") client.queue.resume("") ``` ```go Go package main import ( "github.com/upstash/qstash-go" ) func main() { client := qstash.NewClient("") // error checking is omitted for brevity err := client.Queues().Resume("") } ``` # Upsert a Queue Source: https://upstash.com/docs/qstash/api/queues/upsert POST https://qstash.upstash.io/v2/queues/ Updates or creates a queue ## Request The name of the queue. The number of parallel consumers consuming from [the queue](/qstash/features/queues). For the parallelism limit, we introduced an easier and less limited API with publish. Please check the [Flow Control](/qstash/features/flowcontrol) page for the detailed information. Setting parallelism with queues will be deprecated at some point. ## Response This endpoint returns * 200 if the queue is added successfully. * 412 if it fails because of the the allowed number of queues limit ```sh curl curl -XPOST https://qstash.upstash.io/v2/queues/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "queueName": "my-queue" , "parallelism" : 5, }' ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/queues/', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ "queueName": "my-queue" , "parallelism" : 5, }) }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', } json_data = { "queueName": "my-queue" , "parallelism" : 5, } response = requests.post( 'https://qstash.upstash.io/v2/queues/', headers=headers, json=json_data ) ``` ```go Go var data = strings.NewReader(`{ "queueName": "my-queue" , "parallelism" : 5, }`) req, err := http.NewRequest("POST", "https://qstash.upstash.io/v2/queues/", data) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` # Create Schedule Source: https://upstash.com/docs/qstash/api/schedules/create POST https://qstash.upstash.io/v2/schedules/{destination} Create a schedule to send messages periodically ## Request Destination can either be a topic name or id that you configured in the Upstash console or a valid url where the message gets sent to. If the destination is a URL, make sure the URL is prefixed with a valid protocol (`http://` or `https://`) Cron allows you to send this message periodically on a schedule. Add a Cron expression and we will requeue this message automatically whenever the Cron expression triggers. We offer an easy to use UI for creating Cron expressions in our [console](https://console.upstash.com/qstash) or you can check out [Crontab.guru](https://crontab.guru). Note: it can take up to 60 seconds until the schedule is registered on an available qstash node. Example: `*/5 * * * *` Delay the message delivery. Delay applies to the delivery of the scheduled messages. For example, with the delay set to 10 minutes for a schedule that runs everyday at 00:00, the scheduled message will be created at 00:00 and it will be delivered at 00:10. Format for this header is a number followed by duration abbreviation, like `10s`. Available durations are `s` (seconds), `m` (minutes), `h` (hours), `d` (days). example: "50s" | "3m" | "10h" | "1d" Assign a schedule id to the created schedule. This header allows you to set the schedule id yourself instead of QStash assigning a random id. If a schedule with the provided id exists, the settings of the existing schedule will be updated with the new settings. ## Response The unique id of this schedule. You can use it to delete the schedule later. ```sh curl curl -XPOST https://qstash.upstash.io/v2/schedules/https://www.example.com/endpoint \ -H "Authorization: Bearer " \ -H "Upstash-Cron: */5 * * * *" ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/schedules/https://www.example.com/endpoint', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Upstash-Cron': '*/5 * * * *' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Upstash-Cron': '*/5 * * * *' } response = requests.post( 'https://qstash.upstash.io/v2/schedules/https://www.example.com/endpoint', headers=headers ) ``` ```go Go req, err := http.NewRequest("POST", "https://qstash.upstash.io/v2/schedules/https://www.example.com/endpoint", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Upstash-Cron", "*/5 * * * *") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "scheduleId": "scd_1234" } ``` # Get Schedule Source: https://upstash.com/docs/qstash/api/schedules/get GET https://qstash.upstash.io/v2/schedules/{scheduleId} Retrieves a schedule by id. ## Request The id of the schedule to retrieve. ## Response The creation time of the object. UnixMilli The id of the schedule. The cron expression used to schedule the message. IP address where this schedule created from. Url or URL Group name The HTTP method to use for the message. The headers of the message. The body of the message. The number of retries that should be attempted in case of delivery failure. The delay in seconds before the message is delivered. The url where we send a callback to after the message is delivered ```sh curl curl https://qstash.upstash.io/v2/schedules/scd_1234 \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/schedules/scd_1234', { headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/schedules/scd_1234', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/schedules/scd_1234", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "scheduleId": "scd_1234", "createdAt": 1623345678001, "cron": "0 0 1 * *", "destination": "https://example.com", "method": "POST", "header": { "Content-Type": ["application/json"] }, "body": "{\"message\":\"hello\"}", "retries": 3 } ``` # List Schedules Source: https://upstash.com/docs/qstash/api/schedules/list GET https://qstash.upstash.io/v2/schedules List all your schedules ## Response The creation time of the object. UnixMilli The id of the schedule. The cron expression used to schedule the message. Url or URL Group (topic) name The HTTP method to use for the message. The headers of the message. The body of the message. The number of retries that should be attempted in case of delivery failure. The delay in seconds before the message is delivered. The url where we send a callback to after the message is delivered ```sh curl curl https://qstash.upstash.io/v2/schedules \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/schedules', { headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/schedules', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/schedules", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK [ { "scheduleId": "scd_1234", "createdAt": 1623345678001, "cron": "0 0 1 * *", "destination": "https://example.com", "method": "POST", "header": { "Content-Type": ["application/json"] }, "body": "{\"message\":\"hello\"}", "retries": 3 } ] ``` # Pause Schedule Source: https://upstash.com/docs/qstash/api/schedules/pause POST https://qstash.upstash.io/v2/schedules/{scheduleId}/pause Pause an active schedule Pausing a schedule will not change the next delivery time, but the delivery will be ignored. If the schedule is already paused, this action has no effect. ## Request The id of the schedule to pause. ## Response This endpoint simply returns 200 OK if the schedule is paused successfully. ```sh curl curl -X POST https://qstash.upstash.io/v2/schedules/scd_1234/pause \ -H "Authorization: Bearer " ``` ```js Node import { Client } from "@upstash/qstash"; /** * Import a fetch polyfill only if you are using node prior to v18. * This is not necessary for nextjs, deno or cloudflare workers. */ import "isomorphic-fetch"; const c = new Client({ token: "", }); c.schedules.pause({ schedule: "" }); ``` ```python Python from qstash import QStash client = QStash("") client.schedule.pause("") ``` ```go Go package main import "github.com/upstash/qstash-go" func main() { client := qstash.NewClient("") // error checking is omitted for brevity err := client.Schedules().Pause("") } ``` # Remove Schedule Source: https://upstash.com/docs/qstash/api/schedules/remove DELETE https://qstash.upstash.io/v2/schedules/{scheduleId} Remove a schedule ## Request The schedule id to remove ## Response This endpoint simply returns 200 OK if the schedule is removed successfully. ```sh curl curl -XDELETE https://qstash.upstash.io/v2/schedules/scd_123 \ -H "Authorization: Bearer " ``` ```javascript Node const response = await fetch('https://qstash.upstash.io/v2/schedules/scd_123', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.delete( 'https://qstash.upstash.io/v2/schedules/scd_123', headers=headers ) ``` ```go Go req, err := http.NewRequest("DELETE", "https://qstash.upstash.io/v2/schedules/scd_123", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` # Resume Schedule Source: https://upstash.com/docs/qstash/api/schedules/resume POST https://qstash.upstash.io/v2/schedules/{scheduleId}/resume Resume a paused schedule Resuming a schedule marks the schedule as active. This means the upcoming messages will be delivered and will not be ignored. If the schedule is already active, this action has no effect. ## Request The id of the schedule to resume. ## Response This endpoint simply returns 200 OK if the schedule is resumed successfully. ```sh curl curl -X POST https://qstash.upstash.io/v2/schedules/scd_1234/resume \ -H "Authorization: Bearer " ``` ```js Node import { Client } from "@upstash/qstash"; /** * Import a fetch polyfill only if you are using node prior to v18. * This is not necessary for nextjs, deno or cloudflare workers. */ import "isomorphic-fetch"; const c = new Client({ token: "", }); c.schedules.resume({ schedule: "" }); ``` ```python Python from qstash import QStash client = QStash("") client.schedule.resume("") ``` ```go Go package main import "github.com/upstash/qstash-go" func main() { client := qstash.NewClient("") // error checking is omitted for brevity err := client.Schedules().Resume("") } ``` # Get Signing Keys Source: https://upstash.com/docs/qstash/api/signingKeys/get GET https://qstash.upstash.io/v2/keys Retrieve your signing keys ## Response Your current signing key. The next signing key. ```sh curl curl https://qstash.upstash.io/v2/keys \ -H "Authorization: Bearer " ``` ```javascript Node const response = await fetch('https://qstash.upstash.io/v2/keys', { headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/keys', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/keys", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "current": "sig_123", "next": "sig_456" } ``` # Rotate Signing Keys Source: https://upstash.com/docs/qstash/api/signingKeys/rotate POST https://qstash.upstash.io/v2/keys/rotate Rotate your signing keys ## Response Your current signing key. The next signing key. ```sh curl curl https://qstash.upstash.io/v2/keys/rotate \ -H "Authorization: Bearer " ``` ```javascript Node const response = await fetch('https://qstash.upstash.io/v2/keys/rotate', { headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/keys/rotate', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/keys/rotate", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "current": "sig_123", "next": "sig_456" } ``` # Upsert URL Group and Endpoint Source: https://upstash.com/docs/qstash/api/url-groups/add-endpoint POST https://qstash.upstash.io/v2/topics/{urlGroupName}/endpoints Add an endpoint to a URL Group If the URL Group does not exist, it will be created. If the endpoint does not exist, it will be created. ## Request The name of your URL Group (topic). If it doesn't exist yet, it will be created. The endpoints to add to the URL Group. The name of the endpoint The URL of the endpoint ## Response This endpoint returns 200 if the endpoints are added successfully. ```sh curl curl -XPOST https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "endpoints": [ { "name": "endpoint1", "url": "https://example.com" }, { "name": "endpoint2", "url": "https://somewhere-else.com" } ] }' ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints', { method: 'POST', headers: { 'Authorization': 'Bearer ', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'endpoints': [ { 'name': 'endpoint1', 'url': 'https://example.com' }, { 'name': 'endpoint2', 'url': 'https://somewhere-else.com' } ] }) }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', } json_data = { 'endpoints': [ { 'name': 'endpoint1', 'url': 'https://example.com', }, { 'name': 'endpoint2', 'url': 'https://somewhere-else.com', }, ], } response = requests.post( 'https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints', headers=headers, json=json_data ) ``` ```go Go var data = strings.NewReader(`{ "endpoints": [ { "name": "endpoint1", "url": "https://example.com" }, { "name": "endpoint2", "url": "https://somewhere-else.com" } ] }`) req, err := http.NewRequest("POST", "https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints", data) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` # Get a URL Group Source: https://upstash.com/docs/qstash/api/url-groups/get GET https://qstash.upstash.io/v2/topics/{urlGroupName} Retrieves a URL Group ## Request The name of the URL Group (topic) to retrieve. ## Response The creation time of the URL Group. UnixMilli The update time of the URL Group. UnixMilli The name of the URL Group. The name of the endpoint The URL of the endpoint ```sh curl curl https://qstash.upstash.io/v2/topics/my-url-group \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/topics/my-url-group', { headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/topics/my-url-group', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/topics/my-url-group", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK { "createdAt": 1623345678001, "updatedAt": 1623345678001, "name": "my-url-group", "endpoints": [ { "name": "my-endpoint", "url": "https://my-endpoint.com" } ] } ``` # List URL Groups Source: https://upstash.com/docs/qstash/api/url-groups/list GET https://qstash.upstash.io/v2/topics List all your URL Groups ## Request No parameters ## Response The creation time of the URL Group. UnixMilli The update time of the URL Group. UnixMilli The name of the URL Group. The name of the endpoint. The URL of the endpoint ```sh curl curl https://qstash.upstash.io/v2/topics \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch("https://qstash.upstash.io/v2/topics", { headers: { Authorization: "Bearer ", }, }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.get( 'https://qstash.upstash.io/v2/topics', headers=headers ) ``` ```go Go req, err := http.NewRequest("GET", "https://qstash.upstash.io/v2/topics", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` ```json 200 OK [ { "createdAt": 1623345678001, "updatedAt": 1623345678001, "name": "my-url-group", "endpoints": [ { "name": "my-endpoint", "url": "https://my-endpoint.com" } ] }, // ... ] ``` # Remove URL Group Source: https://upstash.com/docs/qstash/api/url-groups/remove DELETE https://qstash.upstash.io/v2/topics/{urlGroupName} Remove a URL group and all its endpoints The URL Group and all its endpoints are removed. In flight messages in the URL Group are not removed but you will not be able to send messages to the topic anymore. ## Request The name of the URL Group to remove. ## Response This endpoint returns 200 if the URL Group is removed successfully. ```sh curl curl -XDELETE https://qstash.upstash.io/v2/topics/my-url-group \ -H "Authorization: Bearer " ``` ```js Node const response = await fetch('https://qstash.upstash.io/v2/topics/my-url-group', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' } }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', } response = requests.delete( 'https://qstash.upstash.io/v2/topics/my-url-group', headers=headers ) ``` ```go Go req, err := http.NewRequest("DELETE", "https://qstash.upstash.io/v2/topics/my-url-group", nil) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` # Remove Endpoints Source: https://upstash.com/docs/qstash/api/url-groups/remove-endpoint DELETE https://qstash.upstash.io/v2/topics/{urlGroupName}/endpoints Remove one or more endpoints Remove one or multiple endpoints from a URL Group. If all endpoints have been removed, the URL Group will be deleted. ## Request The name of your URL Group. If it doesn't exist, we return an error. The endpoints to be removed from to the URL Group. Either `name` or `url` must be provided The name of the endpoint The URL of the endpoint ## Response This endpoint simply returns 200 OK if the endpoints have been removed successfully. ```sh curl curl -XDELETE https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "endpoints": [ { "name": "endpoint1", }, { "url": "https://somewhere-else.com" } ] }' ``` ```js Node const response = await fetch("https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints", { method: "DELETE", headers: { Authorization: "Bearer ", "Content-Type": "application/json", }, body: { endpoints: [ { name: "endpoint1", }, { url: "https://somewhere-else.com", }, ], }, }); ``` ```python Python import requests headers = { 'Authorization': 'Bearer ', 'Content-Type': 'application/json', } data = { "endpoints": [ { "name": "endpoint1", }, { "url": "https://somewhere-else.com" } ] } response = requests.delete( 'https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints', headers=headers, data=data ) ``` ```go Go var data = strings.NewReader(`{ "endpoints": [ { "name": "endpoint1", }, { "url": "https://somewhere-else.com" } ] }`) req, err := http.NewRequest("DELETE", "https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints", data) if err != nil { log.Fatal(err) } req.Header.Set("Authorization", "Bearer ") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ``` # Background Jobs Source: https://upstash.com/docs/qstash/features/background-jobs ## When do you need background jobs Background jobs are essential for executing tasks that are too time-consuming to run in the main execution thread without affecting the user experience. These tasks might include data processing, sending batch emails, performing scheduled maintenance, or any other operations that are not immediately required to respond to user requests. Utilizing background jobs allows your application to remain responsive and scalable, handling more requests simultaneously by offloading heavy lifting to background processes. In Serverless frameworks, your hosting provider will likely have a limit for how long each task can last. Try searching for the maximum execution time for your hosting provider to find out more. ## How to use QStash for background jobs QStash provides a simple and efficient way to run background jobs, you can understand it as a 2 step process: 1. **Public API** Create a public API endpoint within your application. The endpoint should contain the logic for the background job. QStash requires a public endpoint to trigger background jobs, which means it cannot directly access localhost APIs. To get around this, you have two options: * Run QStash [development server](/qstash/howto/local-development) locally * Set up a [local tunnel](/qstash/howto/local-tunnel) for your API 2. **QStash Request** Invoke QStash to start/schedule the execution of the API endpoint. Here's what this looks like in a simple Next.js application: ```tsx app/page.tsx "use client" export default function Home() { async function handleClick() { // Send a request to our server to start the background job. // For proper error handling, refer to the quick start. // Note: This can also be a server action instead of a route handler await fetch("/api/start-email-job", { method: "POST", body: JSON.stringify({ users: ["a@gmail.com", "b@gmail.com", "c.gmail.com"] }), }) } return (
); } ``` ```typescript app/api/start-email-job/route.ts import { Client } from "@upstash/qstash"; const qstashClient = new Client({ token: "YOUR_TOKEN", }); export async function POST(request: Request) { const body = await request.json(); const users: string[] = body.users; // If you know the public URL of the email API, you can use it directly const rootDomain = request.url.split('/').slice(0, 3).join('/'); const emailAPIURL = `${rootDomain}/api/send-email`; // ie: https://yourapp.com/api/send-email // Tell QStash to start the background job. // For proper error handling, refer to the quick start. await qstashClient.publishJSON({ url: emailAPIURL, body: { users } }); return new Response("Job started", { status: 200 }); } ``` ```typescript app/api/send-email/route.ts // This is a public API endpoint that will be invoked by QStash. // It contains the logic for the background job and may take a long time to execute. import { sendEmail } from "your-email-library"; export async function POST(request: Request) { const body = await request.json(); const users: string[] = body.users; // Send emails to the users for (const user of users) { await sendEmail(user); } return new Response("Job started", { status: 200 }); } ```
To better understand the application, let's break it down: 1. **Client**: The client application contains a button that, when clicked, sends a request to the server to start the background job. 2. **Next.js server**: The first endpoint, `/api/start-email-job`, is invoked by the client to start the background job. 3. **QStash**: The QStash client is used to invoke the `/api/send-email` endpoint, which contains the logic for the background job. Here is a visual representation of the process: Background job diagram Background job diagram To view a more detailed Next.js quick start guide for setting up QStash, refer to the [quick start](/qstash/quickstarts/vercel-nextjs) guide. It's also possible to schedule a background job to run at a later time using [schedules](/qstash/features/schedules). If you'd like to invoke another endpoint when the background job is complete, you can use [callbacks](/qstash/features/callbacks). # Batching Source: https://upstash.com/docs/qstash/features/batch [Publishing](/qstash/howto/publishing) is great for sending one message at a time, but sometimes you want to send a batch of messages at once. This can be useful to send messages to a single or multiple destinations. QStash provides the `batch` endpoint to help you with this. If the format of the messages are valid, the response will be an array of responses for each message in the batch. When batching URL Groups, the response will be an array of responses for each destination in the URL Group. If one message fails to be sent, that message will have an error response, but the other messages will still be sent. You can publish to destination, URL Group or queue in the same batch request. ## Batching messages with destinations You can also send messages to the same destination! ```shell cURL curl -XPOST https://qstash.upstash.io/v2/batch \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d ' [ { "destination": "https://example.com/destination1" }, { "destination": "https://example.com/destination2" } ]' ``` ```typescript TypeScript import { Client } from "@upstash/qstash"; // Each message is the same as the one you would send with the publish endpoint const client = new Client({ token: "" }); const res = await client.batchJSON([ { url: "https://example.com/destination1", }, { url: "https://example.com/destination2", }, ]); ``` ```python Python from qstash import QStash client = QStash("") client.message.batch_json( [ {"url": "https://example.com/destination1"}, {"url": "https://example.com/destination2"}, ] ) ``` ## Batching messages with URL Groups If you have a [URL Group](/qstash/howto/url-group-endpoint), you can batch send with the URL Group as well. ```shell cURL curl -XPOST https://qstash.upstash.io/v2/batch \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d ' [ { "destination": "myUrlGroup" }, { "destination": "https://example.com/destination2" } ]' ``` ```typescript TypeScript const client = new Client({ token: "" }); // Each message is the same as the one you would send with the publish endpoint const res = await client.batchJSON([ { urlGroup: "myUrlGroup", }, { url: "https://example.com/destination2", }, ]); ``` ```python Python from qstash import QStash client = QStash("") client.message.batch_json( [ {"url_group": "my-url-group"}, {"url": "https://example.com/destination2"}, ] ) ``` ## Batching messages with queue If you have a [queue](/qstash/features/queues), you can batch send with the queue. It is the same as publishing to a destination, but you need to set the queue name. ```shell cURL curl -XPOST https://qstash.upstash.io/v2/batch \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d ' [ { "queue": "my-queue", "destination": "https://example.com/destination1" }, { "queue": "my-second-queue", "destination": "https://example.com/destination2" } ]' ``` ```typescript TypeScript const client = new Client({ token: "" }); const res = await client.batchJSON([ { queueName: "my-queue", url: "https://example.com/destination1", }, { queueName: "my-second-queue", url: "https://example.com/destination2", }, ]); ``` ```python Python from upstash_qstash import QStash from upstash_qstash.message import BatchRequest qstash = QStash("") messages = [ BatchRequest( queue="my-queue", url="https://httpstat.us/200", body=f"hi 1", retries=0 ), BatchRequest( queue="my-second-queue", url="https://httpstat.us/200", body=f"hi 2", retries=0 ), ] qstash.message.batch(messages) ``` ## Batching messages with headers and body You can provide custom headers and a body for each message in the batch. ```shell cURL curl -XPOST https://qstash.upstash.io/v2/batch -H "Authorization: Bearer XXX" \ -H "Content-Type: application/json" \ -d ' [ { "destination": "myUrlGroup", "headers":{ "Upstash-Delay":"5s", "Upstash-Forward-Hello":"123456" }, "body": "Hello World" }, { "destination": "https://example.com/destination1", "headers":{ "Upstash-Delay":"7s", "Upstash-Forward-Hello":"789" } }, { "destination": "https://example.com/destination2", "headers":{ "Upstash-Delay":"9s", "Upstash-Forward-Hello":"again" } } ]' ``` ```typescript TypeScript const client = new Client({ token: "" }); // Each message is the same as the one you would send with the publish endpoint const msgs = [ { urlGroup: "myUrlGroup", delay: 5, body: "Hello World", headers: { hello: "123456", }, }, { url: "https://example.com/destination1", delay: 7, headers: { hello: "789", }, }, { url: "https://example.com/destination2", delay: 9, headers: { hello: "again", }, body: { Some: "Data", }, }, ]; const res = await client.batchJSON(msgs); ``` ```python Python from qstash import QStash client = QStash("") client.message.batch_json( [ { "url_group": "my-url-group", "delay": "5s", "body": {"hello": "world"}, "headers": {"random": "header"}, }, { "url": "https://example.com/destination1", "delay": "1m", }, { "url": "https://example.com/destination2", "body": {"hello": "again"}, }, ] ) ``` #### The response for this will look like ```json [ [ { "messageId": "msg_...", "url": "https://myUrlGroup-endpoint1.com" }, { "messageId": "msg_...", "url": "https://myUrlGroup-endpoint2.com" } ], { "messageId": "msg_..." }, { "messageId": "msg_..." } ] ``` # Callbacks Source: https://upstash.com/docs/qstash/features/callbacks All serverless function providers have a maximum execution time for each function. Usually you can extend this time by paying more, but it's still limited. QStash provides a way to go around this problem by using callbacks. ## What is a callback? A callback allows you to call a long running function without having to wait for its response. Instead of waiting for the request to finish, you can add a callback url to your published message and when the request finishes, we will call your callback URL with the response. 1. You publish a message to QStash using the `/v2/publish` endpoint 2. QStash will enqueue the message and deliver it to the destination 3. QStash waits for the response from the destination 4. When the response is ready, QStash calls your callback URL with the response Callbacks publish a new message with the response to the callback URL. Messages created by callbacks are charged as any other message. ## How do I use Callbacks? You can add a callback url in the `Upstash-Callback` header when publishing a message. The value must be a valid URL. ```bash cURL curl -X POST \ https://qstash.upstash.io/v2/publish/https://my-api... \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ -H 'Upstash-Callback: ' \ -d '{ "hello": "world" }' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, callback: "https://my-callback...", }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, callback="https://my-callback...", ) ``` The callback body sent to you will be a JSON object with the following fields: ```json { "status": 200, "header": { "key": ["value"] }, // Response header "body": "YmFzZTY0IGVuY29kZWQgcm9keQ==", // base64 encoded response body "retried": 2, // How many times we retried to deliver the original message "maxRetries": 3, // Number of retries before the message assumed to be failed to delivered. "sourceMessageId": "msg_xxx", // The ID of the message that triggered the callback "topicName": "myTopic", // The name of the URL Group (topic) if the request was part of a URL Group "endpointName": "myEndpoint", // The endpoint name if the endpoint is given a name within a topic "url": "http://myurl.com", // The destination url of the message that triggered the callback "method": "GET", // The http method of the message that triggered the callback "sourceHeader": { "key": "value" }, // The http header of the message that triggered the callback "sourceBody": "YmFzZTY0kZWQgcm9keQ==", // The base64 encoded body of the message that triggered the callback "notBefore": "1701198458025", // The unix timestamp of the message that triggered the callback is/will be delivered in milliseconds "createdAt": "1701198447054", // The unix timestamp of the message that triggered the callback is created in milliseconds "scheduleId": "scd_xxx", // The scheduleId of the message if the message is triggered by a schedule "callerIP": "178.247.74.179" // The IP address where the message that triggered the callback is published from } ``` In Next.js you could use the following code to handle the callback: ```js // pages/api/callback.js import { verifySignature } from "@upstash/qstash/nextjs"; function handler(req, res) { // responses from qstash are base64-encoded const decoded = atob(req.body.body); console.log(decoded); return res.status(200).end(); } export default verifySignature(handler); export const config = { api: { bodyParser: false, }, }; ``` We may truncate the response body if it exceeds your plan limits. You can check your `Max Message Size` in the [console](https://console.upstash.com/qstash?tab=details). Make sure you verify the authenticity of the callback request made to your API by [verifying the signature](/qstash/features/security/#request-signing-optional). # What is a Failure-Callback? Failure callbacks are similar to callbacks but they are called only when all the retries are exhausted and still the message can not be delivered to the given endpoint. This is designed to be an serverless alternative to [List messages to DLQ](/qstash/api/dlq/listMessages). You can add a failure callback URL in the `Upstash-Failure-Callback` header when publishing a message. The value must be a valid URL. ```bash cURL curl -X POST \ https://qstash.upstash.io/v2/publish/ \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ -H 'Upstash-Failure-Callback: ' \ -d '{ "hello": "world" }' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, failureCallback: "https://my-callback...", }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, failure_callback="https://my-callback...", ) ``` The callback body sent to you will be a JSON object with the following fields: ```json { "status": 400, "header": { "key": ["value"] }, // Response header "body": "YmFzZTY0IGVuY29kZWQgcm9keQ==", // base64 encoded response body "retried": 3, // How many times we retried to deliver the original message "maxRetries": 3, // Number of retries before the message assumed to be failed to delivered. "dlqId": "1725323658779-0", // Dead Letter Queue id. This can be used to retrieve/remove the related message from DLQ. "sourceMessageId": "msg_xxx", // The ID of the message that triggered the callback "topicName": "myTopic", // The name of the URL Group (topic) if the request was part of a topic "endpointName": "myEndpoint", // The endpoint name if the endpoint is given a name within a topic "url": "http://myurl.com", // The destination url of the message that triggered the callback "method": "GET", // The http method of the message that triggered the callback "sourceHeader": { "key": "value" }, // The http header of the message that triggered the callback "sourceBody": "YmFzZTY0kZWQgcm9keQ==", // The base64 encoded body of the message that triggered the callback "notBefore": "1701198458025", // The unix timestamp of the message that triggered the callback is/will be delivered in milliseconds "createdAt": "1701198447054", // The unix timestamp of the message that triggered the callback is created in milliseconds "scheduleId": "scd_xxx", // The scheduleId of the message if the message is triggered by a schedule "callerIP": "178.247.74.179" // The IP address where the message that triggered the callback is published from } ``` You can also use a callback and failureCallback together! ## Configuring Callbacks Publishes/enqueues for callbacks can also be configured with the same HTTP headers that are used to configure direct publishes/enqueues. You can refer to headers that are used to configure `publishes` [here](https://upstash.com/docs/qstash/api/publish) and for `enqueues` [here](https://upstash.com/docs/qstash/api/enqueue) Instead of the `Upstash` prefix for headers, the `Upstash-Callback`/`Upstash-Failure-Callback` prefix can be used to configure callbacks as follows: ``` Upstash-Callback-Timeout Upstash-Callback-Retries Upstash-Callback-Delay Upstash-Callback-Method Upstash-Failure-Callback-Timeout Upstash-Failure-Callback-Retries Upstash-Failure-Callback-Delay Upstash-Failure-Callback-Method ``` You can also forward headers to your callback endpoints as follows: ``` Upstash-Callback-Forward-MyCustomHeader Upstash-Failure-Callback-Forward-MyCustomHeader ``` # Deduplication Source: https://upstash.com/docs/qstash/features/deduplication Messages can be deduplicated to prevent duplicate messages from being sent. When a duplicate message is detected, it is accepted by QStash but not enqueued. This can be useful when the connection between your service and QStash fails, and you never receive the acknowledgement. You can simply retry publishing and can be sure that the message will enqueued only once. In case a message is a duplicate, we will accept the request and return the messageID of the existing message. The only difference will be the response status code. We'll send HTTP `202 Accepted` code in case of a duplicate message. ## Deduplication ID To deduplicate a message, you can send the `Upstash-Deduplication-Id` header when publishing the message. ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Deduplication-Id: abcdef" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://my-api..."' ``` ```typescript TypeScript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, deduplicationId: "abcdef", }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, deduplication_id="abcdef", ) ``` ## Content Based Deduplication If you want to deduplicate messages automatically, you can set the `Upstash-Content-Based-Deduplication` header to `true`. ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Content-Based-Deduplication: true" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/...' ``` ```typescript TypeScript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, contentBasedDeduplication: true, }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, content_based_deduplication=True, ) ``` Content based deduplication creates a unique deduplication ID for the message based on the following fields: * **Destination**: The URL Group or endpoint you are publishing the message to. * **Body**: The body of the message. * **Header**: This includes the `Content-Type` header and all headers, that you forwarded with the `Upstash-Forward-` prefix. See [custom HTTP headers section](/qstash/howto/publishing#sending-custom-http-headers). The deduplication window is 10 minutes. After that, messages with the same ID or content can be sent again. # Delay Source: https://upstash.com/docs/qstash/features/delay When publishing a message, you can delay it for a certain amount of time before it will be delivered to your API. See the [pricing table](https://upstash.com/pricing/qstash) for more information For free: The maximum allowed delay is **7 days**. For pay-as-you-go: The maximum allowed delay is **1 year**. For fixed pricing: The maximum allowed delay is **Custom(you may delay as much as needed)**. ## Relative Delay Delay a message by a certain amount of time relative to the time the message was published. The format for the duration is ``. Here are some examples: * `10s` = 10 seconds * `1m` = 1 minute * `30m` = half an hour * `2h` = 2 hours * `7d` = 7 days You can send this duration inside the `Upstash-Delay` header. ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Delay: 1m" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://my-api...' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, delay: 60, }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, headers={ "test-header": "test-value", }, delay="60s", ) ``` `Upstash-Delay` will get overridden by `Upstash-Not-Before` header when both are used together. ## Absolute Delay Delay a message until a certain time in the future. The format is a unix timestamp in seconds, based on the UTC timezone. You can send the timestamp inside the `Upstash-Not-Before` header. ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Not-Before: 1657104947" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://my-api...' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, notBefore: 1657104947, }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, headers={ "test-header": "test-value", }, not_before=1657104947, ) ``` `Upstash-Not-Before` will override the `Upstash-Delay` header when both are used together. ## Delays in Schedules Adding a delay in schedules is only possible via `Upstash-Delay`. The delay will affect the messages that will be created by the schedule and not the schedule itself. For example when you create a new schedule with a delay of `30s`, the messages will be created when the schedule triggers but only delivered after 30 seconds. # Dead Letter Queues Source: https://upstash.com/docs/qstash/features/dlq At times, your API may fail to process a request. This could be due to a bug in your code, a temporary issue with a third-party service, or even network issues. QStash automatically retries messages that fail due to a temporary issue but eventually stops and moves the message to a dead letter queue to be handled manually. Read more about retries [here](/qstash/features/retry). ## How to Use the Dead Letter Queue You can manually republish messages from the dead letter queue in the console. 1. **Retry** - Republish the message and remove it from the dead letter queue. Republished messages are just like any other message and will be retried automatically if they fail. 2. **Delete** - Delete the message from the dead letter queue. ## Limitations Dead letter queues are limited to a certain number of messages. If you exceed this limit, the oldest messages will be dropped. Unhandled messages are evicted after some time. See the [pricing](https://upstash.com/pricing/qstash) page for more information. # Flow Control Source: https://upstash.com/docs/qstash/features/flowcontrol FlowControl enables you to limit the number of messages sent to your endpoint via delaying the delivery. There are two limits that you can set with the FlowControl feature: [Rate](#rate-limit) and [Parallelism](#parallelism-limit). And if needed both parameters can be [combined](#rate-and-parallelism-together). For the `FlowControl`, you need to choose a key first. This key is used to count the number of calls made to your endpoint. There are not limits to number of keys you can use. The rate/parallelism limits are not applied per `url`, they are applied per `Flow-Control-Key`. Keep in mind that rate/period and parallelism info are kept on each publish separately. That means if you change the rate/period or parallelism on a new publish, the old fired ones will not be affected. They will keep their flowControl config. During the period that old `publishes` has not delivered but there are also the `publishes` with the new rates, QStash will effectively allow the highest rate/period or highest parallelism. Eventually(after the old publishes are delivered), the new rate/period and parallelism will be used. ## Rate and Period Parameters The `rate` parameter specifies the maximum number of calls allowed within a given period. The `period` parameter allows you to specify the time window over which the rate limit is enforced. By default, the period is set to 1 second, but you can adjust it to control how frequently calls are allowed. For example, you can set a rate of 10 calls per minute as follows: ```typescript TypeScript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world" }, flowControl: { key: "USER_GIVEN_KEY", rate: 10, period: "1m" }, }); ``` ```bash cURL curl -XPOST -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Flow-Control-Key:USER_GIVEN_KEY" \ -H "Upstash-Flow-Control-Value:rate=10,period=1m" \ 'https://qstash.upstash.io/v2/publish/https://example.com' \ -d '{"message":"Hello, World!"}' ``` ## Parallelism Limit The parallelism limit is the number of calls that can be active at the same time. Active means that the call is made to your endpoint and the response is not received yet. You can set the parallelism limit to 10 calls active at the same time as follows: ```typescript TypeScript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world" }, flowControl: { key: "USER_GIVEN_KEY", parallelism: 10 }, }); ``` ```bash cURL curl -XPOST -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Flow-Control-Key:USER_GIVEN_KEY" \ -H "Upstash-Flow-Control-Value:parallelism=10" \ 'https://qstash.upstash.io/v2/publish/https://example.com' \ -d '{"message":"Hello, World!"}' ``` You can also use the Rest API to get information how many messages waiting for parallelism limit. See the [API documentation](/qstash/api/flow-control/get) for more details. ### Rate, Parallelism, and Period Together All three parameters can be combined. For example, with a rate of 10 per minute, parallelism of 20, and a period of 1 minute, QStash will trigger 10 calls in the first minute and another 10 in the next. Since none of them will have finished, the system will wait until one completes before triggering another. ```typescript TypeScript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world" }, flowControl: { key: "USER_GIVEN_KEY", rate: 10, parallelism: 20, period: "1m" }, }); ``` ```bash cURL curl -XPOST -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Flow-Control-Key:USER_GIVEN_KEY" \ -H "Upstash-Flow-Control-Value:rate=10,parallelism=20,period=1m" \ 'https://qstash.upstash.io/v2/publish/https://example.com' \ -d '{"message":"Hello, World!"}' ``` # Queues Source: https://upstash.com/docs/qstash/features/queues The queue concept in QStash allows ordered delivery (FIFO). See the [API doc](/qstash/api/queues/upsert) for the full list of related Rest APIs. Here we list common use cases for Queue and how to use them. ## Ordered Delivery With Queues, the ordered delivery is guaranteed by default. This means: * Your messages will be queued without blocking the REST API and sent one by one in FIFO order. Queued means [CREATED](/qstash/howto/debug-logs) event will be logged. * The next message will wait for retries of the current one if it can not be delivered because your endpoint returns non-2xx code. In other words, the next message will be [ACTIVE](/qstash/howto/debug-logs) only after the last message is either [DELIVERED](/qstash/howto/debug-logs) or [FAILED](/qstash/howto/debug-logs). * Next message will wait for [callbacks](/qstash/features/callbacks#what-is-a-callback) or [failure callbacks](/qstash/features/callbacks#what-is-a-failure-callback) to finish. ```bash cURL curl -XPOST -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ 'https://qstash.upstash.io/v2/enqueue/my-queue/https://example.com' -d '{"message":"Hello, World!"}' ``` ```typescript TypeScript const client = new Client({ token: "" }); const queue = client.queue({ queueName: "my-queue" }) await queue.enqueueJSON({ url: "https://example.com", body: { "Hello": "World" } }) ``` ```python Python from qstash import QStash client = QStash("") client.message.enqueue_json( queue="my-queue", url="https://example.com", body={ "Hello": "World", }, ) ``` ## Controlled Parallelism For the parallelism limit, we introduced an easier and less limited API with publish. Please check the [Flow Control](/qstash/features/flowcontrol) page for the detailed information. Setting parallelism with queues will be deprecated at some point. To ensure that your endpoint is not overwhelmed and also you want more than one-by-one delivery for better throughput, you can achieve controlled parallelism with queues. By default, queues have parallelism 1. Depending on your [plan](https://upstash.com/pricing/qstash), you can configure the parallelism of your queues as follows: ```bash cURL curl -XPOST https://qstash.upstash.io/v2/queues/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "queueName": "my-queue", "parallelism": 5, }' ``` ```typescript TypeScript const client = new Client({ token: "" }); const queue = client.queue({ queueName: "my-queue" }) await queue.upsert({ parallelism: 1, }) ``` ```python Python from qstash import QStash client = QStash("") client.queue.upsert("my-queue", parallelism=5) ``` After that, you can use the `enqueue` path to send your messages. ```bash cURL curl -XPOST -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ 'https://qstash.upstash.io/v2/enqueue/my-queue/https://example.com' -d '{"message":"Hello, World!"}' ``` ```typescript TypeScript const client = new Client({ token: "" }); const queue = QStashClient.queue({ queueName: "my-queue" }) await queue.enqueueJSON({ url: "https://example.com", body: { "Hello": "World" } }) ``` ```python Python from qstash import QStash client = QStash("") client.message.enqueue_json( queue="my-queue", url="https://example.com", body={ "Hello": "World", }, ) ``` You can check the parallelism of your queues with the following API: ```bash cURL curl https://qstash.upstash.io/v2/queues/my-queue \ -H "Authorization: Bearer " ``` ```typescript TypeScript const client = new Client({ token: "" }); const queue = client.queue({ queueName: "my-queue" }) const res = await queue.get() ``` ```python Python from qstash import QStash client = QStash("") client.queue.get("my-queue") ``` # Retry Source: https://upstash.com/docs/qstash/features/retry For free: Requests will be considered failed if not processed within **15 minutes**. For pay-as-you-go: Requests will be considered failed if not processed within **2 hours**. For fixed pricing: Requests will be considered failed if not processed within **Custom(you may timeout as much as needed)**. Many things can go wrong in a serverless environment. If your API does not respond with a success status code (2XX), we retry the request to ensure every message will be delivered. The maximum number of retries depends on your current plan. By default, we retry the maximum amount of times, but you can set it lower by sending the `Upstash-Retries` header: ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Retries: 2" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://my-api...' ``` ```typescript TypeScript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, retries: 2, }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, retries=2, ) ``` The backoff algorithm calculates the retry delay based on the number of retries. Each delay is capped at 1 day. ``` n = how many times this request has been retried delay = min(86400, e ** (2.5*n)) // in seconds ``` | n | delay | | - | ------ | | 1 | 12s | | 2 | 2m28s | | 3 | 30m8ss | | 4 | 6h7m6s | | 5 | 24h | | 6 | 24h | ## Retry-After Headers Instead of using the default backoff algorithm, you can specify when QStash should retry your message. To do this, include one of the following headers in your response to QStash request. * Retry-After * X-RateLimit-Reset * X-RateLimit-Reset-Requests * X-RateLimit-Reset-Tokens These headers can be set to a value in seconds, the RFC1123 date format, or a duration format (e.g., 6m5s). For the duration format, valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Note that you can only delay retries up to the maximum value of the default backoff algorithm, which is one day. If you specify a value beyond this limit, the backoff algorithm will be applied. This feature is particularly useful if your application has rate limits, ensuring retries are scheduled appropriately without wasting attempts during restricted periods. ``` Retry-After: 0 // Next retry will be scheduled immediately without any delay. Retry-After: 10 // Next retry will be scheduled after a 10-second delay. Retry-After: 6m5s // Next retry will be scheduled after 6 minutes 5 seconds delay. Retry-After: Sun, 27 Jun 2024 12:16:24 GMT // Next retry will be scheduled for the specified date, within the allowable limits. ``` ## Upstash-Retried Header QStash adds the `Upstash-Retried` header to requests sent to your API. This indicates how many times the request has been retried. ``` Upstash-Retried: 0 // This is the first attempt Upstash-Retried: 1 // This request has been sent once before and now is the second attempt Upstash-Retried: 2 // This request has been sent twice before and now is the third attempt ``` # Schedules Source: https://upstash.com/docs/qstash/features/schedules In addition to sending a message once, you can create a schedule, and we will publish the message in the given period. To create a schedule, you simply need to add the `Upstash-Cron` header to your `publish` request. Schedules can be configured using `cron` expressions. [crontab.guru](https://crontab.guru/) is a great tool for understanding and creating cron expressions. We use `UTC` as timezone when evaluating cron expressions. The following request would create a schedule that will automatically publish the message every minute: ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "https://example.com", cron: "* * * * *", }); ``` ```python Python from qstash import QStash client = QStash("") client.schedule.create( destination="https://example.com", cron="* * * * *", ) ``` ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Cron: * * * * *" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/schedules/https://example.com' ``` All of the [other config options](/qstash/howto/publishing#optional-parameters-and-configuration) can still be used. It can take up to 60 seconds for the schedule to be loaded on an active node and triggered for the first time. You can see and manage your schedules in the [Upstash Console](https://console.upstash.com/qstash). ### Scheduling to a URL Group Instead of scheduling a message to a specific URL, you can also create a schedule, that publishes to a URL Group. Simply use either the URL Group name or its id: ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "urlGroupName", cron: "* * * * *", }); ``` ```python Python from qstash import QStash client = QStash("") client.schedule.create( destination="url-group-name", cron="* * * * *", ) ``` ```bash cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Cron: * * * * *" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/schedules/' ``` ### Scheduling to a Queue You can schedule an item to be added to a queue at a specified time. ```bash typescript curl -XPOST \ import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "https://example.com", cron: "* * * * *", queueName: "yourQueueName", }); ``` ```bash cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Cron: * * * * *" \ -H "Upstash-Queue-Name: yourQueueName" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/schedules/https://example.com' ``` ### Overwriting an existing schedule You can pass scheduleId explicitly to overwrite an existing schedule or just simply create the schedule with the given schedule id. ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "https://example.com", scheduleId: "existingScheduleId", cron: "* * * * *", }); ``` ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Cron: * * * * *" \ -H "Upstash-Schedule-Id: existingScheduleId" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/schedules/https://example.com' ``` # Security Source: https://upstash.com/docs/qstash/features/security ### Request Authorization When interacting with the QStash API, you will need an authorization token. You can get your token from the [Console](https://console.upstash.com/qstash). Send this token along with every request made to `QStash` inside the `Authorization` header like this: ``` "Authorization": "Bearer " ``` ### Request Signing (optional) Because your endpoint needs to be publicly available, we recommend you verify the authenticity of each incoming request. #### The `Upstash-Signature` header With each request we are sending a JWT inside the `Upstash-Signature` header. You can learn more about them [here](https://jwt.io). An example token would be: **Header** ```json { "alg": "HS256", "typ": "JWT" } ``` **Payload** ```json { "iss": "Upstash", "sub": "https://qstash-remote.requestcatcher.com/test", "exp": 1656580612, "nbf": 1656580312, "iat": 1656580312, "jti": "jwt_67kxXD6UBAk7DqU6hzuHMDdXFXfP", "body": "qK78N0k3pNKI8zN62Fq2Gm-_LtWkJk1z9ykio3zZvY4=" } ``` The JWT is signed using `HMAC SHA256` algorithm with your current signing key and includes the following claims: #### Claims ##### `iss` The issuer field is always `Upstash`. ##### `sub` The url of your endpoint, where this request is sent to. For example when you are using a nextjs app on vercel, this would look something like `https://my-app.vercel.app/api/endpoint` ##### `exp` A unix timestamp in seconds after which you should no longer accept this request. Our JWTs have a lifetime of 5 minutes by default. ##### `iat` A unix timestamp in seconds when this JWT was created. ##### `nbf` A unix timestamp in seconds before which you should not accept this request. ##### `jti` A unique id for this token. ##### `body` The body field is a base64 encoded sha256 hash of the request body. We use url encoding as specified in [RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5). #### Verifying the signature See [how to verify the signature](/qstash/howto/signature). # URL Groups Source: https://upstash.com/docs/qstash/features/url-groups Sending messages to a single endpoint and not having to worry about retries is already quite useful, but we also added the concept of URL Groups to QStash. In short, a URL Group is just a namespace where you can publish messages to, the same way as publishing a message to an endpoint directly. After creating a URL Group, you can create one or multiple endpoints. An endpoint is defined by a publicly available URL where the request will be sent to each endpoint after it is published to the URL Group. When you publish a message to a URL Group, it will be fanned out and sent to all the subscribed endpoints. ## When should I use URL Groups? URL Groups decouple your message producers from consumers by grouping one or more endpoints into a single namespace. Here's an example: You have a serverless function which is invoked with each purchase in your e-commerce site. You want to send email to the customer after the purchase. Inside the function, you submit the URL `api/sendEmail` to the QStash. Later, if you want to send a Slack notification, you need to update the serverless function adding another call to QStash to submit `api/sendNotification`. In this example, you need to update and redeploy the Serverless function at each time you change (or add) the endpoints. If you create a URL Group `product-purchase` and produce messages to that URL Group in the function, then you can add or remove endpoints by only updating the URL Group. URL Groups give you freedom to modify endpoints without touching the backend implementation. Check [here](/qstash/howto/publishing#publish-to-url-group) to learn how to publish to URL Groups. ## How URL Groups work When you publish a message to a URL Group, we will enqueue a unique task for each subscribed endpoint and guarantee successful delivery to each one of them. [![](https://mermaid.ink/img/pako:eNp1kl1rgzAUhv9KyOWoddXNtrkYVNdf0F0U5ijRHDVMjctHoRT_-2KtaztUQeS8j28e8JxxKhhggpWmGt45zSWtnKMX13GN7PX59IUc5w19iIanBDUmKbkq-qwfXuKdSVQqeQLssK1ZI3itVQ9dekdzdO6Ja9ntKKq-DxtEoP4xYGCIr-OOGCoOG4IYlPwIcqBu0V0XQRK0PE0w9lyCvP1-iB1n1CgcNwofjcJpo_Cua8ooHDWadIrGnaJHp2jaKbrrmnKK_jl1d9s98AxXICvKmd2fy8-MsS6gghgT-5oJCUrH2NKWNA2zi7BlXAuJSUZLBTNMjRa7U51ioqWBAbpu4R9VCsrAfnTG-tR0u5pzpW1lKuqM593cyNKOC60bRVy3i-c514VJ5qmoXMVZQaUujuvADbxgRT0fgqVPX32fpclivcq8l0XGls8Lj-K2bX8Bx2nzPg)](https://mermaid.live/edit#pako:eNp1kl1rgzAUhv9KyOWoddXNtrkYVNdf0F0U5ijRHDVMjctHoRT_-2KtaztUQeS8j28e8JxxKhhggpWmGt45zSWtnKMX13GN7PX59IUc5w19iIanBDUmKbkq-qwfXuKdSVQqeQLssK1ZI3itVQ9dekdzdO6Ja9ntKKq-DxtEoP4xYGCIr-OOGCoOG4IYlPwIcqBu0V0XQRK0PE0w9lyCvP1-iB1n1CgcNwofjcJpo_Cua8ooHDWadIrGnaJHp2jaKbrrmnKK_jl1d9s98AxXICvKmd2fy8-MsS6gghgT-5oJCUrH2NKWNA2zi7BlXAuJSUZLBTNMjRa7U51ioqWBAbpu4R9VCsrAfnTG-tR0u5pzpW1lKuqM593cyNKOC60bRVy3i-c514VJ5qmoXMVZQaUujuvADbxgRT0fgqVPX32fpclivcq8l0XGls8Lj-K2bX8Bx2nzPg) Consider this scenario: You have a URL Group and 3 endpoints that are subscribed to it. Now when you publish a message to the URL Group, internally we will create a task for each subscribed endpoint and handle all retry mechanism isolated from each other. ## How to create a URL Group Please refer to the howto [here](/qstash/howto/url-group-endpoint). # Debug Logs Source: https://upstash.com/docs/qstash/howto/debug-logs To debug the logs, first you need to understand the different states a message can be in. Only the last 10.000 logs are kept and older logs are removed automatically. ## Lifecycle of a Message To understand the lifecycle of each message, we'll look at the following chart: [comment]: # "https://mermaid.live/edit#pako:eNptU9uO2jAQ_RXLjxVXhyTED5UQpBUSZdtAK7VNtfLGTmIpsZHjrEoR_17HBgLdztPMmXPm4ssJZpIyiGGjiWYrTgpF6uErSgUw9vPdLzAcvgfLJF7s45UDL4FNbEnN6FLWB9lwzVz-EbO0xXK__hb_L43Bevv8OXn6mMS7nSPYSf6tcgIXc5zOkniffH9TvrM4SZ4Sm3GcXne-rLDYLuPNcxJ_-Rrvrrs4cGMiRxLS9K1YroHM3yowqFnTkIKBjIiMVYA3xqsqRp3azWQLu3EwaFUFFNOtEg3ICa9uU91xV_HGuIltcM9v2iwz_fpN-u0_LNYbyzdcdQQVr7k2PsnK6yx90Y5vLtXBF-ED1h_CA5wKOICF4hRirVo2gDVTNelCeOoYKdQlq1kKsXEpy0lb6RSm4mxkByJ-SFlflUq2RQlxTqrGRO2B9u_uhpJWy91RZFeNY8WUa6lupEoSykx4gvp46J5wwRtt-mVS5LzocHOABi61PjR4PO7So4Lrsn0ZZbIeN5yWROnyNQrGAQrmBHksCD3iex7NXqbRPEezaU7DyRQReD4PILP9P7n_Yr-N2YYJM8RStkJDHHqRXbfr_RviaDbyQg9NJz7yg9ksCAfwCHGARn6AfC9CKJqiiT83lf_Y85mM5uEsurfzX7VrENs" Either you or a previously setup schedule will create a message. When a message is ready for execution, it will be become `ACTIVE` and a delivery to your API is attempted. If you API responds with a status code between `200 - 299`, the task is considered successful and will be marked as `DELIVERED`. Otherwise the message is being retried if there are any retries left and moves to `RETRY`. If all retries are exhausted, the task has `FAILED` and the message will be moved to the DLQ. During all this a message can be cancelled via [DELETE /v2/messages/:messageId](https://docs.upstash.com/qstash/api/messages/cancel). When the request is received, `CANCEL_REQUESTED` will be logged first. If retries are not exhausted yet, in the next deliver time, the message will be marked as `CANCELLED` and will be completely removed from the system. ## Console Head over to the [Upstash Console](https://console.upstash.com/qstash) and go to the `Logs` tab, where you can see the latest status of your messages. # Delete Schedules Source: https://upstash.com/docs/qstash/howto/delete-schedule Deleting schedules can be done using the [schedules api](/qstash/api/schedules/remove). ```shell cURL curl -XDELETE \ -H 'Authorization: Bearer XXX' \ 'https://qstash.upstash.io/v2/schedules/' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.delete(""); ``` ```python Python from qstash import QStash client = QStash("") client.schedule.delete("") ``` Deleting a schedule does not stop existing messages from being delivered. It only stops the schedule from creating new messages. ## Schedule ID If you don't know the schedule ID, you can get a list of all of your schedules from [here](/qstash/api/schedules/list). ```shell cURL curl \ -H 'Authorization: Bearer XXX' \ 'https://qstash.upstash.io/v2/schedules' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const allSchedules = await client.schedules.list(); ``` ```python Python from qstash import QStash client = QStash("") client.schedule.list() ``` # Handling Failures Source: https://upstash.com/docs/qstash/howto/handling-failures Sometimes, endpoints fail due to various reasons such as network issues or server issues. In such cases, QStash offers a few options to handle these failures. ## Failure Callbacks When publishing a message, you can provide a failure callback that will be called if the message fails to be published. You can read more about callbacks [here](/qstash/features/callbacks). With the failure callback, you can add custom logic such as logging the failure or sending an alert to the team. Once you handle the failure, you can [delete it from the dead letter queue](/qstash/api/dlq/deleteMessage). ```bash cURL curl -X POST \ https://qstash.upstash.io/v2/publish/ \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ -H 'Upstash-Failure-Callback: ' \ -d '{ "hello": "world" }' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, failureCallback: "https://my-callback...", }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, failure_callback="https://my-callback...", ) ``` ## Dead Letter Queue If you don't want to handle the failure immediately, you can use the dead letter queue (DLQ) to store the failed messages. You can read more about the dead letter queue [here](/qstash/features/dlq). Failed messages are automatically moved to the dead letter queue upon failure, and can be retried from the console or the API by [retrieving the message](/qstash/api/dlq/getMessage) then [publishing it](/qstash/api/publish). DLQ from console # Local Development Source: https://upstash.com/docs/qstash/howto/local-development QStash requires a publicly available API to send messages to. During development when applications are not yet deployed, developers typically need to expose their local API by creating a public tunnel. While local tunneling works seamlessly, it requires code changes between development and production environments and increase friction for developers. To simplify the development process, Upstash provides QStash CLI, which allows you to run a development server locally for testing and development. The development server fully supports all QStash features including Schedules, URL Groups, Workflows, and Event Logs. Since the development server operates entirely in-memory, all data is reset when the server restarts. You can download and run the QStash CLI executable binary in several ways: ## NPX (Node Package Executable) Install the binary via the `@upstash/qstash-cli` NPM package: ```javascript npx @upstash/qstash-cli dev // Start on a different port npx @upstash/qstash-cli dev -port=8081 ``` ## Docker QStash CLI is available as a Docker image through our public AWS ECR repository: ```javascript // Pull the image docker pull public.ecr.aws/upstash/qstash:latest // Run the image docker run -p 8080:8080 public.ecr.aws/upstash/qstash:latest qstash dev ``` ## Artifact Repository You can download the binary directly from our artifact repository without using a package manager: [https://artifacts.upstash.com/#qstash/versions/](https://artifacts.upstash.com/#qstash/versions/) Select the appropriate version, architecture, and operating system for your platform. After extracting the archive file, run the executable: ``` $ ./qstash dev ``` ## QStash CLI Currently, the only available command for QStash CLI is `dev`, which starts a development server instance. ``` $ ./qstash dev --help Usage of dev: -port int The port to start HTTP server at [env QSTASH_DEV_PORT] (default 8080) -quota string The quota of users [env QSTASH_DEV_QUOTA] (default "payg") ``` There are predefined test users available. You can configure the quota type of users using the `-quota` option, with available options being `payg` and `pro`. These quotas don't affect performance but allow you to simulate different server limits based on the subscription tier. After starting the development server using any of the methods above, it will display the necessary environment variables. Select and copy the credentials from one of the following test users: ```javascript User 1 QSTASH_URL=http://localhost:8080 QSTASH_TOKEN=eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0= QSTASH_CURRENT_SIGNING_KEY=sig_7kYjw48mhY7kAjqNGcy6cr29RJ6r QSTASH_NEXT_SIGNING_KEY=sig_5ZB6DVzB1wjE8S6rZ7eenA8Pdnhs ``` ```javascript User 2 QSTASH_URL=http://localhost:8080 QSTASH_TOKEN=eyJVc2VySUQiOiJ0ZXN0VXNlcjEiLCJQYXNzd29yZCI6InRlc3RQYXNzd29yZCJ9 QSTASH_CURRENT_SIGNING_KEY=sig_7GVPjvuwsfqF65iC8fSrs1dfYruM QSTASH_NEXT_SIGNING_KEY=sig_5NoELc3EFnZn4DVS5bDs2Nk4b7Ua ``` ```javascript User 3 QSTASH_URL=http://localhost:8080 QSTASH_TOKEN=eyJVc2VySUQiOiJ0ZXN0VXNlcjIiLCJQYXNzd29yZCI6InRlc3RQYXNzd29yZCJ9 QSTASH_CURRENT_SIGNING_KEY=sig_6jWGaWRxHsw4vMSPJprXadyvrybF QSTASH_NEXT_SIGNING_KEY=sig_7qHbvhmahe5GwfePDiS5Lg3pi6Qx ``` ```javascript User 4 QSTASH_URL=http://localhost:8080 QSTASH_TOKEN=eyJVc2VySUQiOiJ0ZXN0VXNlcjMiLCJQYXNzd29yZCI6InRlc3RQYXNzd29yZCJ9 QSTASH_CURRENT_SIGNING_KEY=sig_5T8FcSsynBjn9mMLBsXhpacRovJf QSTASH_NEXT_SIGNING_KEY=sig_7GFR4YaDshFcqsxWRZpRB161jguD ``` Currently, there is no GUI client available for the development server. You can use QStash SDKs to fetch resources like event logs. ## License The QStash development server is licensed under the [Development Server License](/qstash/misc/license), which restricts its use to development and testing purposes only. It is not permitted to use it in production environments. Please refer to the full license text for details. # Local Tunnel Source: https://upstash.com/docs/qstash/howto/local-tunnel QStash requires a publicly available API to send messages to. The recommended approach is to run a [development server](/qstash/howto/local-development) locally and use it for development purposes. Alternatively, you can set up a local tunnel to expose your API, enabling QStash to send requests directly to your application during development. ## localtunnel.me [localtunnel.me](https://github.com/localtunnel/localtunnel) is a free service to provide a public endpoint for your local development. It's as simple as running ``` npx localtunnel --port 3000 ``` replacing `3000` with the port your application is running on. This will give you a public URL like `https://good-months-leave.loca.lt` which can be used as your QStash URL. If you run into issues, you may need to set the `Upstash-Forward-bypass-tunnel-reminder` header to any value to bypass the reminder message. ## ngrok [ngrok](https://ngrok.com) is a free service, that provides you with a public endpoint and forwards all traffic to your localhost. ### Sign up Create a new account on [dashboard.ngrok.com/signup](https://dashboard.ngrok.com/signup) and follow the [instructions](https://dashboard.ngrok.com/get-started/setup) to download the ngrok CLI and connect your account: ```bash ngrok config add-authtoken XXX ``` ### Start the tunnel Choose the port where your application is running. Here I'm forwarding to port 3000, because Next.js is using it. ```bash $ ngrok http 3000 Session Status online Account Andreas Thomas (Plan: Free) Version 3.1.0 Region Europe (eu) Latency - Web Interface http://127.0.0.1:4040 Forwarding https://e02f-2a02-810d-af40-5284-b139-58cc-89df-b740.eu.ngrok.io -> http://localhost:3000 Connections ttl opn rt1 rt5 p50 p90 0 0 0.00 0.00 0.00 0.00 ``` ### Publish a message Now copy the `Forwarding` url and use it as destination in QStash. Make sure to add the path of your API at the end. (`/api/webhooks` in this case) ``` curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://e02f-2a02-810d-af40-5284-b139-58cc-89df-b740.eu.ngrok.io/api/webhooks' ``` ### Debug In case messages are not delivered or something else doesn't work as expected, you can go to [http://127.0.0.1:4040](http://127.0.0.1:4040) to see what ngrok is doing. # Publish Messages Source: https://upstash.com/docs/qstash/howto/publishing Publishing a message is as easy as sending a HTTP request to the `/publish` endpoint. All you need is a valid url of your destination. Destination URLs must always include the protocol (`http://` or `https://`) ## The message The message you want to send is passed in the request body. Upstash does not use, parse, or validate the body, so you can send any kind of data you want. We suggest you add a `Content-Type` header to your request to make sure your destination API knows what kind of data you are sending. ## Sending custom HTTP headers In addition to sending the message itself, you can also forward HTTP headers. Simply add them prefixed with `Upstash-Forward-` and we will include them in the message. #### Here's an example ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H 'Upstash-Forward-My-Header: my-value' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://example.com' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://example.com", body: { "hello": "world" }, headers: { "my-header": "my-value" }, }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, headers={ "my-header": "my-value", }, ) ``` In this case, we would deliver a `POST` request to `https://example.com` with the following body and headers: ```json // body { "hello": "world" } // headers My-Header: my-value Content-Type: application/json ``` #### What happens after publishing? When you publish a message, it will be durably stored in an [Upstash Redis database](https://upstash.com/redis). Then we try to deliver the message to your chosen destination API. If your API is down or does not respond with a success status code (200-299), the message will be retried and delivered when it comes back online. You do not need to worry about retrying messages or ensuring that they are delivered. By default, the multiple messages published to QStash are sent to your API in parallel. ## Publish to URL Group URL Groups allow you to publish a single message to more than one API endpoints. To learn more about URL Groups, check [URL Groups section](/qstash/features/url-groups). Publishing to a URL Group is very similar to publishing to a single destination. All you need to do is replace the `URL` in the `/publish` endpoint with the URL Group name. ``` https://qstash.upstash.io/v2/publish/https://example.com https://qstash.upstash.io/v2/publish/my-url-group ``` ```shell cURL curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/my-url-group' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ urlGroup: "my-url-group", body: { "hello": "world" }, }); ``` ```python Python from qstash import QStash client = QStash("") client.message.publish_json( url_group="my-url-group", body={ "hello": "world", }, ) ``` ## Optional parameters and configuration QStash supports a number of optional parameters and configuration that you can use to customize the delivery of your message. All configuration is done using HTTP headers. # Receiving Messages Source: https://upstash.com/docs/qstash/howto/receiving What do we send to your API? When you publish a message, QStash will deliver it to your chosen destination. This is a brief overview of how a request to your API looks like. ## Headers We are forwarding all headers that have been prefixed with `Upstash-Forward-` to your API. [Learn more](/qstash/howto/publishing#sending-custom-http-headers) In addition to your custom headers, we're sending these headers as well: | Header | Description | | --------------------- | -------------------------------------------------------------------- | | `User-Agent` | Will be set to `Upstash-QStash` | | `Content-Type` | The original `Content-Type` header | | `Upstash-Topic-Name` | The URL Group (topic) name if sent to a URL Group | | `Upstash-Signature` | The signature you need to verify [See here](/qstash/howto/signature) | | `Upstash-Retried` | How often the message has been retried so far. Starts with 0. | | `Upstash-Message-Id` | The message id of the message. | | `Upstash-Schedule-Id` | The schedule id of the message if it is related to a schedule. | | `Upstash-Caller-Ip` | The IP address of the publisher of this message. | ## Body The body is passed as is, we do not modify it at all. If you send a JSON body, you will receive a JSON body. If you send a string, you will receive a string. ## Verifying the signature [See here](/qstash/howto/signature) # Reset Token Source: https://upstash.com/docs/qstash/howto/reset-token Your token is used to interact with the QStash API. You need it to publish messages as well as create, read, update or delete other resources, such as URL Groups and endpoints. Resetting your token will invalidate your current token and all future requests with the old token will be rejected. To reset your token, simply click on the "Reset token" button at the bottom in the [QStash UI](https://console.upstash.com/qstash) and confirm the dialog. ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/reset_token.png) Afterwards you should immediately update your token in all your applications. # Roll Your Signing Keys Source: https://upstash.com/docs/qstash/howto/roll-signing-keys Because your API needs to be publicly accessible from the internet, you should make sure to verify the authenticity of each request. Upstash provides a JWT with each request. This JWT is signed by your individual secret signing keys. [Read more](/qstash/howto/signature). We are using 2 signing keys: * current: This is the key used to sign the JWT. * next: This key will be used to sign after you have rolled your keys. If we were using only a single key, there would be some time between when you rolled your keys and when you can edit the key in your applications. In order to minimize downtime, we use 2 keys and you should always try to verify with both keys. ## What happens when I roll my keys? When you roll your keys, the current key will be replaced with the next key and a new next key will be generated. ``` currentKey = nextKey nextKey = generateNewKey() ``` Rolling your keys twice without updating your applications will cause your apps to reject all requests, because both the current and next keys will have been replaced. ## How to roll your keys Rolling your keys can be done by going to the [QStash UI](https://console.upstash.com/qstash) and clicking on the "Roll keys" button. ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/roll_keys.png) # Verify Signatures Source: https://upstash.com/docs/qstash/howto/signature We send a JWT with each request. This JWT is signed by your individual secret signing key and sent in the `Upstash-Signature` HTTP header. You can use this signature to verify the request is coming from QStash. ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/signing-key-logic.png) You need to keep your signing keys in a secure location. Otherwise some malicious actor could use them to send requests to your API as if they were coming from QStash. ## Verifying You can use the official QStash SDKs or implement a custom verifier either by using [an open source library](https://jwt.io/libraries) or by processing the JWT manually. ### Via SDK (Recommended) QStash SDKs provide a `Receiver` type that simplifies signature verification. ```typescript Typescript import { Receiver } from "@upstash/qstash"; const receiver = new Receiver({ currentSigningKey: "YOUR_CURRENT_SIGNING_KEY", nextSigningKey: "YOUR_NEXT_SIGNING_KEY", }); // ... in your request handler const signature = req.headers["Upstash-Signature"]; const body = req.body; const isValid = receiver.verify({ body, signature, url: "YOUR-SITE-URL", }); ``` ```python Python from qstash import Receiver receiver = Receiver( current_signing_key="YOUR_CURRENT_SIGNING_KEY", next_signing_key="YOUR_NEXT_SIGNING_KEY", ) # ... in your request handler signature, body = req.headers["Upstash-Signature"], req.body receiver.verify( body=body, signature=signature, url="YOUR-SITE-URL", ) ``` ```go Golang import "github.com/qstash/qstash-go" receiver := qstash.NewReceiver("", "NEXT_SIGNING_KEY") // ... in your request handler signature := req.Header.Get("Upstash-Signature") body, err := io.ReadAll(req.Body) // handle err err := receiver.Verify(qstash.VerifyOptions{ Signature: signature, Body: string(body), Url: "YOUR-SITE-URL", // optional }) // handle err ``` Depending on the environment, the body might be parsed into an object by the HTTP handler if it is JSON. Ensure you use the raw body string as is. For example, converting the parsed object back to a string (e.g., JSON.stringify(object)) may cause inconsistencies and result in verification failure. ### Manual verification If you don't want to use the SDKs, you can implement your own verifier either by using an open-source library or by manually processing the JWT. The exact implementation depends on the language of your choice and the library if you use one. Instead here are the steps you need to follow: 1. Split the JWT into its header, payload and signature 2. Verify the signature 3. Decode the payload and verify the claims * `iss`: The issuer must be`Upstash`. * `sub`: The subject must the url of your API. * `exp`: Verify the token has not expired yet. * `nbf`: Verify the token is already valid. * `body`: Hash the raw request body using `SHA-256` and compare it with the `body` claim. You can also reference the implementation in our [Typescript SDK](https://github.com/upstash/sdk-qstash-ts/blob/main/src/receiver.ts#L82). After you have verified the signature and the claims, you can be sure the request came from Upstash and process it accordingly. ## Claims All claims in the JWT are listed [here](/qstash/features/security#claims) # Create URL Groups and Endpoints Source: https://upstash.com/docs/qstash/howto/url-group-endpoint QStash allows you to group multiple APIs together into a single namespace, called a `URL Group` (Previously, it was called `Topics`). Read more about URL Groups [here](/qstash/features/url-groups). There are two ways to create endpoints and URL Groups: The UI and the REST API. ## UI Go to [console.upstash.com/qstash](https://console.upstash.com/qstash) and click on the `URL Groups` tab. Afterwards you can create a new URL Group by giving it a name. Keep in mind that URL Group names are restricted to alphanumeric, underscore, hyphen and dot characters. ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/create_topic.png) After creating the URL Group, you can add endpoints to it: ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/create_endpoint.png) ## API You can create a URL Group and endpoint using the [console](https://console.upstash.com/qstash) or [REST API](/qstash/api/url-groups/add-endpoint). ```bash cURL curl -XPOST https://qstash.upstash.io/v2/topics/:urlGroupName/endpoints \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "endpoints": [ { "name": "endpoint1", "url": "https://example.com" }, { "name": "endpoint2", "url": "https://somewhere-else.com" } ] }' ``` ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const urlGroups = client.urlGroups; await urlGroups.addEndpoints({ name: "urlGroupName", endpoints: [ { name: "endpoint1", url: "https://example.com" }, { name: "endpoint2", url: "https://somewhere-else.com" }, ], }); ``` ```python Python from qstash import QStash client = QStash("") client.url_group.upsert_endpoints( url_group="url-group-name", endpoints=[ {"name": "endpoint1", "url": "https://example.com"}, {"name": "endpoint2", "url": "https://somewhere-else.com"}, ], ) ``` # Use as Webhook Receiver Source: https://upstash.com/docs/qstash/howto/webhook You can configure QStash to receive and process your webhook calls. Instead of having the webhook service call your endpoint directly, QStash acts as an intermediary, receiving the request and forwarding it to your endpoint. QStash provides additional control over webhook requests, allowing you to configure properties such as delay, retries, timeouts, callbacks, and flow control. There are multiple ways to configure QStash to receive webhook requests. ## 1. Publish You can configure your webhook URL as a QStash publish request. For example, if your webhook endpoint is: `https://example.com/api/webhook` Instead of using this URL directly as the webhook address, use: `https://qstash.upstash.io/v2/publish/https://example.com/api/webhook?qstash_token=` Request configurations such as custom retries, timeouts, and other settings can be specified using HTTP headers in the publish request. Refer to the [REST API documentation](/qstash/api/publish) for a full list of available configuration headers. It’s also possible to pass configuration via query parameters. You can use the lowercase format of headers as the key, such as ?upstash-retries=3\&upstash-delay=100s. This makes it easier to configure webhook messages. By default, any headers in the publish request that are prefixed with `Upstash-Forward-` will be forwarded to your endpoint. However, since most webhook services do not allow header prefixing, we introduced a configuration option to enable forwarding all incoming request headers. To enable this, set `Upstash-Header-Forward: true` in the publish request or append the query parameter `?upstash-header-forward=true` to the request URL. This ensures that all headers are forwarded to your endpoint without requiring the `Upstash-Forward-` prefix. ## 2. URL Group URL Groups allow you to define server-side templates for publishing messages. You can create a URL Group either through the UI or programmatically. For example, if your webhook endpoint is: `https://example.com/api/webhook` Instead of using this URL directly, you can create a URL Group and add this URL as an endpoint. `https://qstash.upstash.io/v2/publish/?qstash_token=` You can define default headers for a URL Group, which will automatically apply to all requests sent to that group. ``` curl -X PATCH https://qstash.upstash.io/v2/topics/ \ -H "Authorizarion: Bearer " -d '{ "headers": { "Upstash-Header-Forward": ["true"], "Upstash-Retries": "3" } }' ``` When you save this header for your URL Group, it ensures that all headers are forwarded as needed for your webhook processing. A URL Group also enables you to define multiple endpoints within group. When a publish request is made to a URL Group, all associated endpoints will be triggered, allowing you to fan-out a single webhook call to multiple destinations. # LLM with Anthropic Source: https://upstash.com/docs/qstash/integrations/anthropic QStash integrates smoothly with Anthropic's API, allowing you to send LLM requests and leverage QStash features like retries, callbacks, and batching. This is especially useful when working in serverless environments where LLM response times vary and traditional timeouts may be limiting. QStash provides an HTTP timeout of up to 2 hours, which is ideal for most LLM cases. ### Example: Publishing and Enqueueing Requests Specify the `api` as `llm` with the provider set to `anthropic()` when publishing requests. Use the `Upstash-Callback` header to handle responses asynchronously, as streaming completions aren’t supported for this integration. #### Publishing a Request ```typescript import { anthropic, Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.publishJSON({ api: { name: "llm", provider: anthropic({ token: "" }) }, body: { model: "claude-3-5-sonnet-20241022", messages: [{ role: "user", content: "Summarize recent tech trends." }], }, callback: "https://example.com/callback", }); ``` ### Enqueueing a Chat Completion Request Use `enqueueJSON` with Anthropic as the provider to enqueue requests for asynchronous processing. ```typescript import { anthropic, Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const result = await client.queue({ queueName: "your-queue-name" }).enqueueJSON({ api: { name: "llm", provider: anthropic({ token: "" }) }, body: { model: "claude-3-5-sonnet-20241022", messages: [ { role: "user", content: "Generate ideas for a marketing campaign.", }, ], }, callback: "https://example.com/callback", }); console.log(result); ``` ### Sending Chat Completion Requests in Batches Use `batchJSON` to send multiple requests at once. Each request in the batch specifies the same Anthropic provider and includes a callback URL. ```typescript import { anthropic, Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const result = await client.batchJSON([ { api: { name: "llm", provider: anthropic({ token: "" }) }, body: { model: "claude-3-5-sonnet-20241022", messages: [ { role: "user", content: "Describe the latest in AI research.", }, ], }, callback: "https://example.com/callback1", }, { api: { name: "llm", provider: anthropic({ token: "" }) }, body: { model: "claude-3-5-sonnet-20241022", messages: [ { role: "user", content: "Outline the future of remote work.", }, ], }, callback: "https://example.com/callback2", }, // Add more requests as needed ]); console.log(result); ``` #### Analytics with Helicone To monitor usage, include Helicone analytics by passing your Helicone API key under `analytics`: ```typescript await client.publishJSON({ api: { name: "llm", provider: anthropic({ token: "" }), analytics: { name: "helicone", token: process.env.HELICONE_API_KEY! }, }, body: { model: "claude-3-5-sonnet-20241022", messages: [{ role: "user", content: "Hello!" }] }, callback: "https://example.com/callback", }); ``` With this setup, Anthropic can be used seamlessly in any LLM workflows in QStash. # LLM - OpenAI Source: https://upstash.com/docs/qstash/integrations/llm QStash has built-in support for calling LLM APIs. This allows you to take advantage of QStash features such as retries, callbacks, and batching while using LLM APIs. QStash is especially useful for LLM processing because LLM response times are often highly variable. When accessing LLM APIs from serverless runtimes, invocation timeouts are a common issue. QStash offers an HTTP timeout of 2 hours, which is sufficient for most LLM use cases. By using callbacks and the workflows, you can easily manage the asynchronous nature of LLM APIs. ## QStash LLM API You can publish (or enqueue) single LLM request or batch LLM requests using all existing QStash features natively. To do this, specify the destination `api` as `llm` with a valid provider. The body of the published or enqueued message should contain a valid chat completion request. For these integrations, you must specify the `Upstash-Callback` header so that you can process the response asynchronously. Note that streaming chat completions cannot be used with them. Use [the chat API](#chat-api) for streaming completions. All the examples below can be used with **OpenAI-compatible LLM providers**. ### Publishing a Chat Completion Request ```js JavaScript import { Client, upstash } from "@upstash/qstash"; const client = new Client({ token: "", }); const result = await client.publishJSON({ api: { name: "llm", provider: openai({ token: "_OPEN_AI_TOKEN_"}) }, body: { model: "gpt-3.5-turbo", messages: [ { role: "user", content: "Write a hello world program in Rust.", }, ], }, callback: "https://abc.requestcatcher.com/", }); console.log(result); ``` ```python Python from qstash import QStash from qstash.chat import upstash q = QStash("") result = q.message.publish_json( api={"name": "llm", "provider": openai("")}, body={ "model": "gpt-3.5-turbo", "messages": [ { "role": "user", "content": "Write a hello world program in Rust.", } ], }, callback="https://abc.requestcatcher.com/", ) print(result) ``` ### Enqueueing a Chat Completion Request ```js JavaScript import { Client, upstash } from "@upstash/qstash"; const client = new Client({ token: "", }); const result = await client.queue({ queueName: "queue-name" }).enqueueJSON({ api: { name: "llm", provider: openai({ token: "_OPEN_AI_TOKEN_"}) }, body: { "model": "gpt-3.5-turbo", messages: [ { role: "user", content: "Write a hello world program in Rust.", }, ], }, callback: "https://abc.requestcatcher.com", }); console.log(result); ``` ```python Python from qstash import QStash from qstash.chat import upstash q = QStash("") result = q.message.enqueue_json( queue="queue-name", api={"name": "llm", "provider": openai("")}, body={ "model": "gpt-3.5-turbo", "messages": [ { "role": "user", "content": "Write a hello world program in Rust.", } ], }, callback="https://abc.requestcatcher.com", ) print(result) ``` ### Sending Chat Completion Requests in Batches ```js JavaScript import { Client, upstash } from "@upstash/qstash"; const client = new Client({ token: "", }); const result = await client.batchJSON([ { api: { name: "llm", provider: openai({ token: "_OPEN_AI_TOKEN_" }) }, body: { ... }, callback: "https://abc.requestcatcher.com", }, ... ]); console.log(result); ``` ```python Python from qstash import QStash from qstash.chat import upstash q = QStash("") result = q.message.batch_json( [ { "api":{"name": "llm", "provider": openai("")}, "body": {...}, "callback": "https://abc.requestcatcher.com", }, ... ] ) print(result) ``` ```shell curl curl "https://qstash.upstash.io/v2/batch" \ -X POST \ -H "Authorization: Bearer QSTASH_TOKEN" \ -H "Content-Type: application/json" \ -d '[ { "destination": "api/llm", "body": {...}, "callback": "https://abc.requestcatcher.com" }, ... ]' ``` ### Retrying After Rate Limit Resets When the rate limits are exceeded, QStash automatically schedules the retry of publish or enqueue of chat completion tasks depending on the reset time of the rate limits. That helps with not doing retries prematurely when it is definitely going to fail due to exceeding rate limits. ## Analytics via Helicone Helicone is a powerful observability platform that provides valuable insights into your LLM usage. Integrating Helicone with QStash is straightforward. To enable Helicone observability in QStash, you simply need to pass your Helicone API key when initializing your model. Here's how to do it for both custom models and OpenAI: ```ts import { Client, custom } from "@upstash/qstash"; const client = new Client({ token: "", }); await client.publishJSON({ api: { name: "llm", provider: custom({ token: "XXX", baseUrl: "https://api.together.xyz", }), analytics: { name: "helicone", token: process.env.HELICONE_API_KEY! }, }, body: { model: "meta-llama/Llama-3-8b-chat-hf", messages: [ { role: "user", content: "hello", }, ], }, callback: "https://oz.requestcatcher.com/", }); ``` # Pipedream Source: https://upstash.com/docs/qstash/integrations/pipedream Build and run workflows with 1000s of open source triggers and actions across 900+ apps. [Pipedream](https://pipedream.com) allows you to build and run workflows with 1000s of open source triggers and actions across 900+ apps. Check out the [official integration](https://pipedream.com/apps/qstash). ## Trigger a Pipedream workflow from a QStash topic message This is a step by step guide on how to trigger a Pipedream workflow from a QStash topic message. Alternatively [click here](https://pipedream.com/new?h=tch_3egfAX) to create a new workflow with this QStash topic trigger added. ### 1. Create a Topic in QStash If you haven't yet already, create a **Topic** in the [QStash dashboard](https://console.upstash.com/qstash?tab=topics). ### 2. Create a new Pipedream workflow Sign into [Pipedream](https://pipedream.com) and create a new workflow. ### 3. Add QStash Topic Message as a trigger In the workflow **Trigger** search for QStash and select the **Create Topic Endpoint** trigger. ![Select the QStash Create Topic Endpoint trigger](https://res.cloudinary.com/pipedreamin/image/upload/v1664298855/docs/components/CleanShot_2022-09-27_at_13.13.56_x6gzgk.gif) Then, connect your QStash account by clicking the QStash prop and retrieving your token from the [QStash dashboard](https://console.upstash.com/qstash?tab=details). After connecting your QStash account, click the **Topic** prop, a dropdown will appear containing the QStash topics on your account. Then *click* on a specific topic to listen for new messages on. ![Selecting a QStash topic to subscribe to](https://res.cloudinary.com/pipedreamin/image/upload/v1664299016/docs/components/CleanShot_2022-09-27_at_13.16.35_rewzbo.gif) Finally, *click* **Continue**. Pipedream will create a unique HTTP endpoint and add it to your QStash topic. ### 4. Test with a sample message Use the *Request Builder* in the [QStash dashboard](https://console.upstash.com/qstash?tab=details) to publish a test message to your topic. Alternatively, you can use the **Create topic message** action in a Pipedream workflow to send a message to your topic. *Don't forget* to use this action in a separate workflow, otherwise you might cause an infinite loop of messages between QStash and Pipedream. ### 5. Add additional steps Add additional steps to the workflow by clicking the plus icon beneath the Trigger step. Build a workflow with the 1,000+ pre-built components available in Pipedream, including [Airtable](https://pipedream.com/apps/airtable), [Google Sheets](https://pipedream.com/apps/google-sheets), [Slack](https://pipedream.com/apps/slack) and many more. Alternatively, use [Node.js](https://pipedream.com/docs/code/nodejs) or [Python](https://pipedream.com/docs/code/python) code steps to retrieve, transform, or send data to other services. ### 6. Deploy your Pipedream workflow After you're satisfied with your changes, click the **Deploy** button in the top right of your Pipedream workflow. Your deployed workflow will not automatically process new messages to your QStash topic. Collapse quickstart-trigger-pipedream-workflow-from-topic.md 3 KB ### Video tutorial If you prefer video, you can check out this tutorial by [pipedream](https://pipedream.com). [![Video](https://img.youtube.com/vi/-oXlWuxNG5A/0.jpg)](https://www.youtube.com/watch?v=-oXlWuxNG5A) ## Trigger a Pipedream workflow from a QStash topic message This is a step by step guide on how to trigger a Pipedream workflow from a QStash endpoint message. Alternatively [click here](https://pipedream.com/new?h=tch_m5ofX6) to create a pre-configured workflow with the HTTP trigger and QStash webhook verification step already added. ### 1. Create a new Pipedream workflow Sign into [Pipedream](https://pipedream.com) and create a new workflow. ### 2. Configure the workflow with an HTTP trigger In the workflow **Trigger** select the **New HTTP / Webhook Requests** option. ![Create new HTTP Webhook trigger](https://res.cloudinary.com/pipedreamin/image/upload/v1664296111/docs/components/CleanShot_2022-09-27_at_12.27.42_cqzolg.png) Pipedream will create a unique HTTP endpoint for your workflow. Then configure the HTTP trigger to *return a custom response*. By default Pipedream will always return a 200 response, which allows us to return a non-200 response to QStash to retry the workflow again if there's an error during the execution of the QStash message. ![Configure the webhook to return a custom response](https://res.cloudinary.com/pipedreamin/image/upload/v1664296210/docs/components/CleanShot_2022-09-27_at_12.29.45_jbwtcm.png) Lastly, set the **Event Body** to be a **Raw request**. This will make sure the QStash verify webhook action receives the data in the correct format. ![Set the event body to a raw body](https://res.cloudinary.com/pipedreamin/image/upload/v1664302540/docs/components/CleanShot_2022-09-27_at_14.15.15_o4xinz.png) ### 3. Test with a sample message Use the *Request Builder* in the [QStash dashboard](https://console.upstash.com/qstash?tab=details) to publish a test message to your topic. Alternatively, you can use the **Create topic message** action in a Pipedream workflow to send a message to your topic. *Don't forget* to use this action in a separate workflow, otherwise you might cause an infinite loop of messages between QStash and Pipedream. ### 4. Verify the QStash webhook Pipedream has a pre-built QStash action that will verify the content of incoming webhooks from QStash. First, search for **QStash** in the step search bar, then select the QStash app. Of the available actions, select the **Verify Webhook** action. Then connect your QStash account and select the **HTTP request** prop. In the dropdown, click **Enter custom expression** and then paste in `{{ steps.trigger.event }}`. This step will automatically verify the incoming HTTP requests and exit the workflow early if requests are not from QStash. ### 5. Add additional steps Add additional steps to the workflow by clicking the plus icon beneath the Trigger step. Build a workflow with the 1,000+ pre-built components available in Pipedream, including [Airtable](https://pipedream.com/apps/airtable), [Google Sheets](https://pipedream.com/apps/google-sheets), [Slack](https://pipedream.com/apps/slack) and many more. Alternatively, use [Node.js](https://pipedream.com/docs/code/nodejs) or [Python](https://pipedream.com/docs/code/python) code steps to retrieve, transform, or send data to other services. ### 6. Return a 200 response In the final step of your workflow, return a 200 response by adding a new step and selecting **Return an HTTP Response**. ![Returning an HTTP response](https://res.cloudinary.com/pipedreamin/image/upload/v1664296812/docs/components/CleanShot_2022-09-27_at_12.39.25_apkngf.png) This will generate Node.js code to return an HTTP response to QStash using the `$.respond` helper in Pipedream. ### 7. Deploy your Pipedream workflow After you're satisfied with your changes, click the **Deploy** button in the top right of your Pipedream workflow. Your deployed workflow will not automatically process new messages to your QStash topic. ### Video tutorial If you prefer video, you can check out this tutorial by [pipedream](https://pipedream.com). [![Video](https://img.youtube.com/vi/uG8eO7BNok4/0.jpg)](https://youtu.be/uG8eO7BNok4) # Email - Resend Source: https://upstash.com/docs/qstash/integrations/resend The `qstash-js` SDK offers an integration to easily send emails using [Resend](https://resend.com/), streamlining email delivery in your applications. ## Basic Email Sending To send a single email, use the `publishJSON` method with the `resend` provider. Ensure your `QSTASH_TOKEN` and `RESEND_TOKEN` are set for authentication. ```typescript import { Client, resend } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.publishJSON({ api: { name: "email", provider: resend({ token: "" }), }, body: { from: "Acme ", to: ["delivered@resend.dev"], subject: "Hello World", html: "

It works!

", }, }); ``` In the `body` field, specify any parameters supported by [the Resend Send Email API](https://resend.com/docs/api-reference/emails/send-email), such as `from`, `to`, `subject`, and `html`. ## Sending Batch Emails To send multiple emails at once, use Resend’s [Batch Email API](https://resend.com/docs/api-reference/emails/send-batch-emails). Set the `batch` option to `true` to enable batch sending. Each email configuration is defined as an object within the `body` array. ```typescript await client.publishJSON({ api: { name: "email", provider: resend({ token: "", batch: true }), }, body: [ { from: "Acme ", to: ["foo@gmail.com"], subject: "Hello World", html: "

It works!

", }, { from: "Acme ", to: ["bar@outlook.com"], subject: "World Hello", html: "

It works!

", }, ], }); ``` Each entry in the `body` array represents an individual email, allowing customization of `from`, `to`, `subject`, `html`, and any other Resend-supported fields. # Development Server License Agreement Source: https://upstash.com/docs/qstash/misc/license ## 1. Purpose and Scope This software is a development server implementation of QStash API ("Development Server") provided for testing and development purposes only. It is not intended for production use, commercial deployment, or as a replacement for the official QStash service. ## 2. Usage Restrictions By using this Development Server, you agree to the following restrictions: a) The Development Server may only be used for: * Local development and testing * Continuous Integration (CI) testing * Educational purposes * API integration development b) The Development Server may NOT be used for: * Production environments * Commercial service offerings * Public-facing applications * Operating as a Software-as-a-Service (SaaS) * Reselling or redistributing as a service ## 3. Restrictions on Modification and Reverse Engineering You may not: * Decompile, reverse engineer, disassemble, or attempt to derive the source code of the Development Server * Modify, adapt, translate, or create derivative works based upon the Development Server * Remove, obscure, or alter any proprietary rights notices within the Development Server * Attempt to bypass or circumvent any technical limitations or security measures in the Development Server ## 4. Technical Limitations Users acknowledge that the Development Server: * Operates entirely in-memory without persistence * Provides limited functionality compared to the official service * Offers no data backup or recovery mechanisms * Has no security guarantees * May have performance limitations * Does not implement all features of the official service ## 5. Warranty Disclaimer THE DEVELOPMENT SERVER IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. THE AUTHORS OR COPYRIGHT HOLDERS SHALL NOT BE LIABLE FOR ANY CLAIMS, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF THE SOFTWARE IN VIOLATION OF THIS LICENSE. ## 6. Termination Your rights under this license will terminate automatically if you fail to comply with any of its terms. Upon termination, you must cease all use of the Development Server. ## 7. Acknowledgment By using the Development Server, you acknowledge that you have read this license, understand it, and agree to be bound by its terms. # API Examples Source: https://upstash.com/docs/qstash/overall/apiexamples ### Use QStash via: * cURL * [Typescript SDK](https://github.com/upstash/sdk-qstash-ts) * [Python SDK](https://github.com/upstash/qstash-python) Below are some examples to get you started. You can also check the [how to](/qstash/howto/publishing) section for more technical details or the [API reference](/qstash/api/messages) to test the API. ### Publish a message to an endpoint Simple example to [publish](/qstash/howto/publishing) a message to an endpoint. ```shell curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://example.com' ``` ```typescript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world", }, }); ``` ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://example.com", body={ "hello": "world", }, ) # Async version is also available ``` ### Publish a message to a URL Group The [URL Group](/qstash/features/url-groups) is a way to publish a message to multiple endpoints in a fan out pattern. ```shell curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/myUrlGroup' ``` ```typescript const client = new Client({ token: "" }); await client.publishJSON({ urlGroup: "myUrlGroup", body: { hello: "world", }, }); ``` ```python from qstash import QStash client = QStash("") client.message.publish_json( url_group="my-url-group", body={ "hello": "world", }, ) # Async version is also available ``` ### Publish a message with 5 minutes delay Add a delay to the message to be published. After QStash receives the message, it will wait for the specified time (5 minutes in this example) before sending the message to the endpoint. ```shell curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Delay: 5m" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://example.com' ``` ```typescript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world", }, delay: 300, }); ``` ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://example.com", body={ "hello": "world", }, delay="5m", ) # Async version is also available ``` ### Send a custom header Add a custom header to the message to be published. ```shell curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H 'Upstash-Forward-My-Header: my-value' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://example.com' ``` ```typescript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world", }, headers: { "My-Header": "my-value", }, }); ``` ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://example.com", body={ "hello": "world", }, headers={ "My-Header": "my-value", }, ) # Async version is also available ``` ### Schedule to run once a day ```shell curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Upstash-Cron: 0 0 * * *" \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/schedules/https://example.com' ``` ```typescript const client = new Client({ token: "" }); await client.schedules.create({ destination: "https://example.com", cron: "0 0 * * *", }); ``` ```python from qstash import QStash client = QStash("") client.schedule.create( destination="https://example.com", cron="0 0 * * *", ) # Async version is also available ``` ### Publish messages to a FIFO queue By default, messges are published concurrently. With a [queue](/qstash/features/queues), you can enqueue messages in FIFO order. ```shell curl -XPOST -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ 'https://qstash.upstash.io/v2/enqueue/my-queue/https://example.com' -d '{"message":"Hello, World!"}' ``` ```typescript const client = new Client({ token: "" }); const queue = client.queue({ queueName: "my-queue" }) await queue.enqueueJSON({ url: "https://example.com", body: { "Hello": "World" } }) ``` ```python from qstash import QStash client = QStash("") client.message.enqueue_json( queue="my-queue", url="https://example.com", body={ "Hello": "World", }, ) # Async version is also available ``` ### Publish messages in a [batch](/qstash/features/batch) Publish multiple messages in a single request. ```shell curl -XPOST https://qstash.upstash.io/v2/batch \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -d ' [ { "destination": "https://example.com/destination1" }, { "destination": "https://example.com/destination2" } ]' ``` ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.batchJSON([ { url: "https://example.com/destination1", }, { url: "https://example.com/destination2", }, ]); ``` ```python from qstash import QStash client = QStash("") client.message.batch_json( [ { "url": "https://example.com/destination1", }, { "url": "https://example.com/destination2", }, ] ) # Async version is also available ``` ### Set max retry count to 3 Configure how many times QStash should retry to send the message to the endpoint before sending it to the [dead letter queue](/qstash/features/dlq). ```shell curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Upstash-Retries: 3" \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://example.com' ``` ```typescript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world", }, retries: 3, }); ``` ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://example.com", body={ "hello": "world", }, retries=3, ) # Async version is also available ``` ### Set callback url Receive a response from the endpoint and send it to the specified callback URL. If the endpoint does not return a response, QStash will send it to the failure callback URL. ```shell curl -XPOST \ -H 'Authorization: Bearer XXX' \ -H "Content-type: application/json" \ -H "Upstash-Callback: https://example.com/callback" \ -H "Upstash-Failure-Callback: https://example.com/failure" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://example.com' ``` ```typescript const client = new Client({ token: "" }); await client.publishJSON({ url: "https://example.com", body: { hello: "world", }, callback: "https://example.com/callback", failureCallback: "https://example.com/failure", }); ``` ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://example.com", body={ "hello": "world", }, callback="https://example.com/callback", failure_callback="https://example.com/failure", ) # Async version is also available ``` ### Get message logs Retrieve logs for all messages that have been published (filtering is also available). ```shell curl https://qstash.upstash.io/v2/logs \ -H "Authorization: Bearer XXX" ``` ```typescript const client = new Client({ token: "" }); const logs = await client.logs() ``` ```python from qstash import QStash client = QStash("") client.event.list() # Async version is also available ``` ### List all schedules ```shell curl https://qstash.upstash.io/v2/schedules \ -H "Authorization: Bearer XXX" ``` ```typescript const client = new Client({ token: "" }); const scheds = await client.schedules.list(); ``` ```python from qstash import QStash client = QStash("") client.schedule.list() # Async version is also available ``` # Changelog Source: https://upstash.com/docs/qstash/overall/changelog Workflow changelogs are [here](/workflow/changelog) * **TypeScript SDK (`qstash-js`):** * Added `flow control period` and deprecated `ratePerSecond`. See [here](https://github.com/upstash/qstash-js/pull/237). * Added `IN_PROGRESS` state filter. See [here](https://github.com/upstash/qstash-js/pull/236). * Full changelog, including all fixes, is available [here](https://github.com/upstash/qstash-js/compare/v2.7.23...v2.8.1). * **Python SDK (`qstash-py`):** * Added `IN_PROGRESS` state filter. See [here](https://github.com/upstash/qstash-js/pull/236). * Added various missing features: Callback Headers, Schedule with Queue, Overwrite Schedule ID, Flow Control Period. See [here](https://github.com/upstash/qstash-py/pull/41). * Full changelog, including all fixes, is available [here](https://github.com/upstash/qstash-py/compare/v2.0.5...v3.0.0). * **Console:** * Improved logs tab behavior to prevent collapsing or unnecessary refreshes, increasing usability. * **QStash Server:** * Added support for filtering messages by `FlowControlKey` (Console and SDK support in progress). * Applied performance improvements for bulk cancel operations. * Applied performance improvements for bulk publish operations. * Fixed an issue where scheduled publishes with queues would reset queue parallelism to 1. * Added support for updating existing queue parallelisms even when the max queue limit is reached. * Applied several additional performance optimizations. * **QStash Server:** * Added support for `flow-control period`, allowing users to define a period for a given rate—up to 1 week.\ Previously, the period was fixed at 1 second.\ For example, `rate: 3 period: 1d` means publishes will be throttled to 3 per day. * Applied several performance optimizations. * **Console:** * Added `IN_PROGRESS` as a filter option when grouping by message ID, making it easier to query in-flight messages.\ See [here](https://upstash.com/docs/qstash/howto/debug-logs#lifecycle-of-a-message) for an explanation of message states. * **TypeScript SDK (`qstash-js`):** * Renamed `events` to `logs` for clarity when referring to QStash features. `client.events()` is now deprecated, and `client.logs()` has been introduced. See [details here](https://github.com/upstash/qstash-js/pull/225). * For all fixes, see the full changelog [here](https://github.com/upstash/qstash-js/compare/v2.7.22...v2.7.23). * **QStash Server:** * Fixed an issue where messages with delayed callbacks were silently failing. Now, such messages are explicitly rejected during insertion. * **Python SDK (`qstash-py`):** * Flow Control Parallelism and Rate. See [here](https://github.com/upstash/qstash-py/pull/36) * Addressed a few minor bugs. See the full changelog [here](https://github.com/upstash/qstash-py/compare/v2.0.3...v2.0.5) * **QStash Server:** * Introduced RateLimit and Parallelism controls to manage the rate and concurrency of message processing. Learn more [here](/qstash/features/flowcontrol). * Improved connection timeout detection mechanism to enhance scalability. * Added several new features to better support webhook use cases: * Support for saving headers in a URL group. See [here](/qstash/howto/webhook#2-url-group). * Ability to pass configuration parameters via query strings instead of headers. See [here](/qstash/howto/webhook#1-publish). * Introduced a new `Upstash-Header-Forward` header to forward all headers from the incoming request. See [here](/qstash/howto/webhook#1-publish). * **Python SDK (`qstash-py`):** * Addressed a few minor bugs. See the full changelog [here](https://github.com/upstash/qstash-py/compare/v2.0.2...v2.0.3). * **Local Development Server:** * The local development server is now publicly available. This server allows you to test your Qstash setup locally. Learn more about the local development server [here](https://upstash.com/docs/qstash/howto/local-development). * **Console:** * Separated the Workflow and QStash consoles for an improved user experience. * Separated their DLQ messages as well. * **QStash Server:** * The core team focused on RateLimit and Parallelism features. These features are ready on the server and will be announced next month after the documentation and SDKs are completed. * **TypeScript SDK (`qstash-js`):** * Added global headers to the client, which are automatically included in every publish request. * Resolved issues related to the Anthropics and Resend integrations. * Full changelog, including all fixes, is available [here](https://github.com/upstash/qstash-js/compare/v2.7.17...v2.7.20). * **Python SDK (`qstash-py`):** * Introduced support for custom `schedule_id` values. * Enabled passing headers to callbacks using the `Upstash-Callback-Forward-...` prefix. * Full changelog, including all fixes, is available [here](https://github.com/upstash/qstash-py/compare/v2.0.0...v2.0.1). * **Qstash Server:** * Finalized the local development server, now almost ready for public release. * Improved error reporting by including the field name in cases of invalid input. * Increased the maximum response body size for batch use cases to 100 MB per REST call. * Extended event retention to up to 14 days, instead of limiting to the most recent 10,000 events. Learn more on the [Pricing page](https://upstash.com/pricing/qstash). * **TypeScript SDK (qstash-js):** * Added support for the Anthropics provider and refactored the `api` field of `publishJSON`. See the documentation [here](https://upstash.com/docs/qstash/integrations/anthropic). * Full changelog, including fixes, is available [here](https://github.com/upstash/qstash-js/compare/v2.7.14...v2.7.17). * **Qstash Server:** * Fixed a bug in schedule reporting. The Upstash-Caller-IP header now correctly reports the user’s IP address instead of an internal IP for schedules. * Validated the scheduleId parameter. The scheduleId must now be alphanumeric or include hyphens, underscores, or periods. * Added filtering support to bulk message cancellation. Users can now delete messages matching specific filters. See Rest API [here](https://upstash.com/docs/qstash/api/messages/bulk-cancel). * Resolved a bug that caused the DLQ Console to become unusable when data was too large. * Fixed an issue with queues that caused them to stop during temporary network communication problems with the storage layer. * **TypeScript SDK (qstash-js):** * Fixed a bug on qstash-js where we skipped using the next signing key when the current signing key fails to verify the `upstash-signature`. Released with qstash-js v2.7.14. * Added resend API. See [here](/qstash/integrations/resend). Released with qstash-js v2.7.14. * Added `schedule to queues` feature to the qstash-js. See [here](/qstash/features/schedules#scheduling-to-a-queue). Released with qstash-js v2.7.14. * **Console:** * Optimized the console by trimming event bodies, reducing resource usage and enabling efficient querying of events with large payloads. * **Qstash Server:** * Began development on a new architecture to deliver faster event processing on the server. * Added more fields to events in the [REST API](/qstash/api/events/list), including `Timeout`, `Method`, `Callback`, `CallbackHeaders`, `FailureCallback`, `FailureCallbackHeaders`, and `MaxRetries`. * Enhanced retry backoff logic by supporting additional headers for retry timing. Along with `Retry-After`, Qstash now recognizes `X-RateLimit-Reset`, `X-RateLimit-Reset-Requests`, and `X-RateLimit-Reset-Tokens` as backoff time indicators. See [here](/qstash/features/retry#retry-after-headers) for more details. * Improved performance, resulting in reduced latency for average publish times. * Set the `nbf` (not before) claim on Signing Keys to 0. This claim specifies the time before which the JWT must not be processed. Previously, this was incorrectly used, causing validation issues when there were minor clock discrepancies between systems. * Fixed queue name validation. Queue names must now be alphanumeric or include hyphens, underscores, or periods, consistent with other API resources. * Resolved bugs related to [overwriting a schedule](/qstash/features/schedules#overwriting-an-existing-schedule). * Released [Upstash Workflow](https://upstash.com/docs/qstash/workflow). * Fixed a bug where paused schedules were mistakenly resumed after a process restart (typically occurring during new version releases). * Big update on the UI, where all the Rest functinality exposed in the Console. * Addded order query parameter to [/v2/events](https://upstash.com/docs/qstash/api/events/list) and [/v2/dlq](https://upstash.com/docs/qstash/api/dlq/listMessages) endpoints. * Added [ability to configure](https://upstash.com/docs/qstash/features/callbacks#configuring-callbacks) callbacks(/failure\_callbacks) * A critical fix for schedule pause and resume Rest APIs where the endpoints were not working at all before the fix. * Pause and resume for scheduled messages * Pause and resume for queues * [Bulk cancel](https://upstash.com/docs/qstash/api/messages/bulk-cancel) messages * Body and headers on [events](https://upstash.com/docs/qstash/api/events/list) * Fixed inaccurate queue lag * [Retry-After](https://upstash.com/docs/qstash/features/retry#retry-after-header) support for rate-limited endpoints * [Upstash-Timeout](https://upstash.com/docs/qstash/api/publish) header * [Queues and parallelism](https://upstash.com/docs/qstash/features/queues) * [Event filtering](https://upstash.com/docs/qstash/api/events/list) * [Batch publish messages](https://upstash.com/docs/qstash/api/messages/batch) * [Bulk delete](https://upstash.com/docs/qstash/api/dlq/deleteMessages) for DLQ * Added [failure callback support](https://upstash.com/docs/qstash/api/schedules/create) to scheduled messages * Added Upstash-Caller-IP header to outgoing messages. See \[[https://upstash.com/docs/qstash/howto/receiving](https://upstash.com/docs/qstash/howto/receiving)] for all headers * Added Schedule ID to [events](https://upstash.com/docs/qstash/api/events/list) and [messages](https://upstash.com/docs/qstash/api/messages/get) * Put last response in DLQ * DLQ [get message](https://upstash.com/docs/qstash/api/dlq/getMessage) * Pass schedule ID to the header when calling the user's endpoint * Added more information to [callbacks](https://upstash.com/docs/qstash/features/callbacks) * Added [Upstash-Failure-Callback](https://upstash.com/docs/qstash/features/callbacks#what-is-a-failure-callback) # Compare Source: https://upstash.com/docs/qstash/overall/compare In this section, we will compare QStash with alternative solutions. ### BullMQ BullMQ is a message queue for NodeJS based on Redis. BullMQ is open source project, you can run BullMQ yourself. * Using BullMQ in serverless environments is problematic due to stateless nature of serverless. QStash is designed for serverless environments. * With BullMQ, you need to run a stateful application to consume messages. QStash calls the API endpoints, so you do not need your application to consume messages continuously. * You need to run and maintain BullMQ and Redis yourself. QStash is completely serverless, you maintain nothing and pay for just what you use. ### Zeplo Zeplo is a message queue targeting serverless. Just like QStash it allows users to queue and schedule HTTP requests. While Zeplo targets serverless, it has a fixed monthly price in paid plans which is \$39/month. In QStash, price scales to zero, you do not pay if you are not using it. With Zeplo, you can send messages to a single endpoint. With QStash, in addition to endpoint, you can submit messages to a URL Group which groups one or more endpoints into a single namespace. Zeplo does not have URL Group functionality. ### Quirrel Quirrel is a job queueing service for serverless. It has a similar functionality with QStash. Quirrel is acquired by Netlify, some of its functionality is available as Netlify scheduled functions. QStash is platform independent, you can use it anywhere. # Getting Started Source: https://upstash.com/docs/qstash/overall/getstarted QStash is a **serverless messaging and scheduling solution**. It fits easily into your existing workflow and allows you to build reliable systems without managing infrastructure. Instead of calling an endpoint directly, QStash acts as a middleman between you and an API to guarantee delivery, perform automatic retries on failure, and more. We have a new SDK called [Upstash Workflow](/workflow/getstarted). **Upstash Workflow SDK** is **QStash** simplified for your complex applications * Skip the details of preparing a complex dependent endpoints. * Focus on the essential parts. * Enjoy automatic retries and delivery guarantees. * Avoid platform-specific timeouts. Check out [Upstash Workflow Getting Started](/workflow/getstarted) for more. ## Quick Start Check out these Quick Start guides to get started with QStash in your application. Build a Next application that uses QStash to start a long-running job on your platform Build a Python application that uses QStash to schedule a daily job that clean up a database Or continue reading to learn how to send your first message! ## Send your first message **Prerequisite** You need an Upstash account before publishing messages, create one [here](https://console.upstash.com). ### Public API Make sure you have a publicly available HTTP API that you want to send your messages to. If you don't, you can use something like [requestcatcher.com](https://requestcatcher.com/), [webhook.site](https://webhook.site/) or [webhook-test.com](https://webhook-test.com/) to try it out. For example, you can use this URL to test your messages: [https://firstqstashmessage.requestcatcher.com](https://firstqstashmessage.requestcatcher.com) ### Get your token Go to the [Upstash Console](https://console.upstash.com/qstash) and copy the `QSTASH_TOKEN`. ### Publish a message A message can be any shape or form: json, xml, binary, anything, that can be transmitted in the http request body. We do not impose any restrictions other than a size limit of 1 MB (which can be customized at your request). In addition to the request body itself, you can also send HTTP headers. Learn more about this in the [message publishing section](/qstash/howto/publishing). ```bash cURL curl -XPOST \ -H 'Authorization: Bearer ' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://' ``` ```bash cURL RequestCatcher curl -XPOST \ -H 'Authorization: Bearer ' \ -H "Content-type: application/json" \ -d '{ "hello": "world" }' \ 'https://qstash.upstash.io/v2/publish/https://firstqstashmessage.requestcatcher.com/test' ``` Don't worry, we have SDKs for different languages so you don't have to make these requests manually. ### Check Response You should receive a response with a unique message ID. ### Check Message Status Head over to [Upstash Console](https://console.upstash.com/qstash) and go to the `Logs` tab where you can see your message activities. Learn more about different states [here](/qstash/howto/debug-logs). ## Features and Use Cases Run long-running tasks in the background, without blocking your application Schedule messages to be delivered at a time in the future Publish messages to multiple endpoints, in parallel, using URL Groups Enqueue messages to be delivered one by one in the order they have enqueued. Custom rate per second and parallelism limits to avoid overflowing your endpoint. Get a response delivered to your API when a message is delivered Use a Dead Letter Queue to have full control over failed messages Prevent duplicate messages from being delivered Publish, enqueue, or batch chat completion requests using large language models with QStash features. # llms.txt Source: https://upstash.com/docs/qstash/overall/llms-txt # Pricing & Limits Source: https://upstash.com/docs/qstash/overall/pricing Please check our [pricing page](https://upstash.com/pricing/qstash) for the most up-to-date information on pricing and limits. # Use Cases Source: https://upstash.com/docs/qstash/overall/usecases TODO: andreas: rework and reenable this page after we have 2 use cases ready [https://linear.app/upstash/issue/QSTH-84/use-cases-summaryhighlights-of-recipes](https://linear.app/upstash/issue/QSTH-84/use-cases-summaryhighlights-of-recipes) This section is still a work in progress. We will be adding detailed tutorials for each use case soon. Tell us on [Discord](https://discord.gg/w9SenAtbme) or [X](https://x.com/upstash) what you would like to see here. ### Triggering Nextjs Functions on a schedule Create a schedule in QStash that runs every hour and calls a Next.js serverless function hosted on Vercel. ### Reset Billing Cycle in your Database Once a month, reset database entries to start a new billing cycle. ### Fanning out alerts to Slack, email, Opsgenie, etc. Createa QStash URL Group that receives alerts from a single source and delivers them to multiple destinations. ### Send delayed message when a new user signs up Publish delayed messages whenever a new user signs up in your app. After a certain delay (e.g. 10 minutes), QStash will send a request to your API, allowing you to email the user a welcome message. # AWS Lambda (Node) Source: https://upstash.com/docs/qstash/quickstarts/aws-lambda/nodejs ## Setting up a Lambda The [AWS CDK](https://aws.amazon.com/cdk/) is the most convenient way to create a new project on AWS Lambda. For example, it lets you directly define integrations such as APIGateway, a tool to make our lambda publicly available as an API, in your code. ```bash Terminal mkdir my-app cd my-app cdk init app -l typescript npm i esbuild @upstash/qstash mkdir lambda touch lambda/index.ts ``` ## Webhook verification ### Using the SDK (recommended) Edit `lambda/index.ts`, the file containing our core lambda logic: ```ts lambda/index.ts import { Receiver } from "@upstash/qstash" import type { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda" const receiver = new Receiver({ currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY ?? "", nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY ?? "", }) export const handler = async ( event: APIGatewayProxyEvent ): Promise => { const signature = event.headers["upstash-signature"] const lambdaFunctionUrl = `https://${event.requestContext.domainName}` if (!signature) { return { statusCode: 401, body: JSON.stringify({ message: "Missing signature" }), } } try { await receiver.verify({ signature: signature, body: event.body ?? "", url: lambdaFunctionUrl, }) } catch (err) { return { statusCode: 401, body: JSON.stringify({ message: "Invalid signature" }), } } // Request is valid, perform business logic return { statusCode: 200, body: JSON.stringify({ message: "Request processed successfully" }), } } ``` We'll set the `QSTASH_CURRENT_SIGNING_KEY` and `QSTASH_NEXT_SIGNING_KEY` environment variables together when deploying our Lambda. ### Manual Verification In this section, we'll manually verify our incoming QStash requests without additional packages. Also see our [manual verification example](https://github.com/upstash/qstash-examples/tree/main/aws-lambda). 1. Implement the handler function ```ts lambda/index.ts import type { APIGatewayEvent, APIGatewayProxyResult } from "aws-lambda" import { createHash, createHmac } from "node:crypto" export const handler = async ( event: APIGatewayEvent, ): Promise => { const signature = event.headers["upstash-signature"] ?? "" const currentSigningKey = process.env.QSTASH_CURRENT_SIGNING_KEY ?? "" const nextSigningKey = process.env.QSTASH_NEXT_SIGNING_KEY ?? "" const url = `https://${event.requestContext.domainName}` try { // Try to verify the signature with the current signing key and if that fails, try the next signing key // This allows you to roll your signing keys once without downtime await verify(signature, currentSigningKey, event.body, url).catch((err) => { console.error( `Failed to verify signature with current signing key: ${err}` ) return verify(signature, nextSigningKey, event.body, url) }) } catch (err) { const message = err instanceof Error ? err.toString() : err return { statusCode: 400, body: JSON.stringify({ error: message }), } } // Add your business logic here return { statusCode: 200, body: JSON.stringify({ message: "Request processed successfully" }), } } ``` 2. Implement the `verify` function: ```ts lambda/index.ts /** * @param jwt - The content of the `upstash-signature` header (JWT) * @param signingKey - The signing key to use to verify the signature (Get it from Upstash Console) * @param body - The raw body of the request * @param url - The public URL of the lambda function */ async function verify( jwt: string, signingKey: string, body: string | null, url: string ): Promise { const split = jwt.split(".") if (split.length != 3) { throw new Error("Invalid JWT") } const [header, payload, signature] = split if ( signature != createHmac("sha256", signingKey) .update(`${header}.${payload}`) .digest("base64url") ) { throw new Error("Invalid JWT signature") } // JWT is verified, start looking at payload claims const p: { sub: string iss: string exp: number nbf: number body: string } = JSON.parse(Buffer.from(payload, "base64url").toString()) if (p.iss !== "Upstash") { throw new Error(`invalid issuer: ${p.iss}, expected "Upstash"`) } if (p.sub !== url) { throw new Error(`invalid subject: ${p.sub}, expected "${url}"`) } const now = Math.floor(Date.now() / 1000) if (now > p.exp) { throw new Error("token has expired") } if (now < p.nbf) { throw new Error("token is not yet valid") } if (body != null) { if ( p.body.replace(/=+$/, "") != createHash("sha256").update(body).digest("base64url") ) { throw new Error("body hash does not match") } } } ``` You can find the complete example [here](https://github.com/upstash/qstash-examples/blob/main/aws-lambda/typescript-example/index.ts). ## Deploying a Lambda ### Using the AWS CDK (recommended) Because we used the AWS CDK to initialize our project, deployment is straightforward. Edit the `lib/.ts` file the CDK created when bootstrapping the project. For example, if our lambda webhook does video processing, it could look like this: ```ts lib/.ts import * as cdk from "aws-cdk-lib"; import * as lambda from "aws-cdk-lib/aws-lambda"; import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; import { Construct } from "constructs"; import path from "path"; import * as apigateway from 'aws-cdk-lib/aws-apigateway'; export class VideoProcessingStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props) // Create the Lambda function const videoProcessingLambda = new NodejsFunction(this, 'VideoProcessingLambda', { runtime: lambda.Runtime.NODEJS_20_X, handler: 'handler', entry: path.join(__dirname, '../lambda/index.ts'), }); // Create the API Gateway const api = new apigateway.RestApi(this, 'VideoProcessingApi', { restApiName: 'Video Processing Service', description: 'This service handles video processing.', defaultMethodOptions: { authorizationType: apigateway.AuthorizationType.NONE, }, }); api.root.addMethod('POST', new apigateway.LambdaIntegration(videoProcessingLambda)); } } ``` Every time we now run the following deployment command in our terminal, our changes are going to be deployed right to a publicly available API, authorized by our QStash webhook logic from before. ```bash Terminal cdk deploy ``` You may be prompted to confirm the necessary AWS permissions during this process, for example allowing APIGateway to invoke your lambda function. Once your code has been deployed to Lambda, you'll receive a live URL to your endpoint via the CLI and can see the new APIGateway connection in your AWS dashboard: The URL you use to invoke your function typically follows this format, especially if you follow the same stack configuration as shown above: `https://.execute-api..amazonaws.com/prod/` To provide our `QSTASH_CURRENT_SIGNING_KEY` and `QSTASH_NEXT_SIGNING_KEY` environment variables, navigate to your QStash dashboard: and make these two variables available to your Lambda in your function configuration: Tada, we just deployed a live Lambda with the AWS CDK! šŸŽ‰ ### Manual Deployment 1. Create a new Lambda function by going to the [AWS dashboard](https://us-east-1.console.aws.amazon.com/lambda/home?region=us-east-1#/create/function) for your desired lambda region. Give your new function a name and select `Node.js 20.x` as runtime, then create the function. 2. To make this Lambda available under a public URL, navigate to the `Configuration` tab and click `Function URL`: 3. In the following dialog, you'll be asked to select one of two authentication types. Select `NONE`, because we are handling authentication ourselves. Then, click `Save`. You'll see the function URL on the right side of your function overview: 4. Get your current and next signing key from the [Upstash Console](https://console.upstash.com/qstash). 5. Still under the `Configuration` tab, set the `QSTASH_CURRENT_SIGNING_KEY` and `QSTASH_NEXT_SIGNING_KEY` environment variables: 6. Add the following script to your `package.json` file to build and zip your code: ```json package.json { "scripts": { "build": "rm -rf ./dist; esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js && cd dist && zip -r index.zip index.js*" } } ``` 7. Click the `Upload from` button for your Lambda and deploy the code to AWS. Select `./dist/index.zip` as the upload file. Tada, you've manually deployed a zip file to AWS Lambda! šŸŽ‰ ## Testing the Integration To make sure everything works as expected, navigate to your QStash request builder and send a request to your freshly deployed Lambda function: Alternatively, you can also send a request via CURL: ```bash Terminal curl --request POST "https://qstash.upstash.io/v2/publish/" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d "{ \"hello\": \"world\"}" ``` # AWS Lambda (Python) Source: https://upstash.com/docs/qstash/quickstarts/aws-lambda/python [Source Code](https://github.com/upstash/qstash-examples/tree/main/aws-lambda/python-example) This is a step by step guide on how to receive webhooks from QStash in your Lambda function on AWS. ### 1. Create a new project Let's create a new folder called `aws-lambda` and initialize a new project by creating `lambda_function.py` This example uses Makefile, but the scripts can also be written for `Pipenv`. ```bash mkdir aws-lambda cd aws-lambda touch lambda_function.py ``` ### 2. Dependencies We are using `PyJwt` for decoding the JWT token in our code. We will install the package in the zipping stage. ### 3. Creating the handler function In this example we will show how to receive a webhook from QStash and verify the signature. First, let's import everything we need: ```python import json import os import hmac import hashlib import base64 import time import jwt ``` Now, we create the handler function. In the handler we will prepare all necessary variables that we need for verification. This includes the signature, the signing keys and the url of the lambda function. Then we try to verify the request using the current signing key and if that fails we will try the next one. If the signature could be verified, we can start processing the request. ```python def lambda_handler(event, context): # parse the inputs current_signing_key = os.environ['QSTASH_CURRENT_SIGNING_KEY'] next_signing_key = os.environ['QSTASH_NEXT_SIGNING_KEY'] headers = event['headers'] signature = headers['upstash-signature'] url = "https://{}{}".format(event["requestContext"]["domainName"], event["rawPath"]) body = None if 'body' in event: body = event['body'] # check verification now try: verify(signature, current_signing_key, body, url) except Exception as e: print("Failed to verify signature with current signing key:", e) try: verify(signature, next_signing_key, body, url) except Exception as e2: return { "statusCode": 400, "body": json.dumps({ "error": str(e2), }), } # Your logic here... return { "statusCode": 200, "body": json.dumps({ "message": "ok", }), } ``` The `verify` function will handle the actual verification of the signature. The signature itself is actually a [JWT](https://jwt.io) and includes claims about the request. See [here](/qstash/features/security#claims). ```python # @param jwt_token - The content of the `upstash-signature` header # @param signing_key - The signing key to use to verify the signature (Get it from Upstash Console) # @param body - The raw body of the request # @param url - The public URL of the lambda function def verify(jwt_token, signing_key, body, url): split = jwt_token.split(".") if len(split) != 3: raise Exception("Invalid JWT.") header, payload, signature = split message = header + '.' + payload generated_signature = base64.urlsafe_b64encode(hmac.new(bytes(signing_key, 'utf-8'), bytes(message, 'utf-8'), digestmod=hashlib.sha256).digest()).decode() if generated_signature != signature and signature + "=" != generated_signature : raise Exception("Invalid JWT signature.") decoded = jwt.decode(jwt_token, options={"verify_signature": False}) sub = decoded['sub'] iss = decoded['iss'] exp = decoded['exp'] nbf = decoded['nbf'] decoded_body = decoded['body'] if iss != "Upstash": raise Exception("Invalid issuer: {}".format(iss)) if sub.rstrip("/") != url.rstrip("/"): raise Exception("Invalid subject: {}".format(sub)) now = time.time() if now > exp: raise Exception("Token has expired.") if now < nbf: raise Exception("Token is not yet valid.") if body != None: while decoded_body[-1] == "=": decoded_body = decoded_body[:-1] m = hashlib.sha256() m.update(bytes(body, 'utf-8')) m = m.digest() generated_hash = base64.urlsafe_b64encode(m).decode() if generated_hash != decoded_body and generated_hash != decoded_body + "=" : raise Exception("Body hash doesn't match.") ``` You can find the complete file [here](https://github.com/upstash/qstash-examples/tree/main/aws-lambda/python-example/lambda_function.py). That's it, now we can create the function on AWS and test it. ### 4. Create a Lambda function on AWS Create a new Lambda function from scratch by going to the [AWS console](https://us-east-1.console.aws.amazon.com/lambda/home?region=us-east-1#/create/function). (Make sure you select your desired region) Give it a name and select `Python 3.8` as runtime, then create the function. Afterwards we will add a public URL to this lambda by going to the `Configuration` tab: Select `Auth Type = NONE` because we are handling authentication ourselves. After creating the url, you should see it on the right side of the overview of your function: ### 5. Set Environment Variables Get your current and next signing key from the [Upstash Console](https://console.upstash.com/qstash) On the same `Configuration` tab from earlier, we will now set the required environment variables: ### 6. Deploy your Lambda function We need to bundle our code and zip it to deploy it to AWS. Add the following script to your `Makefile` file (or corresponding pipenv script): ```yaml zip: rm -rf dist pip3 install --target ./dist pyjwt cp lambda_function.py ./dist/lambda_function.py cd dist && zip -r lambda.zip . mv ./dist/lambda.zip ./ ``` When calling `make zip` this will install PyJwt and zip the code. Afterwards we can click the `Upload from` button in the lower right corner and deploy the code to AWS. Select `lambda.zip` as upload file. ### 7. Publish a message Open a different terminal and publish a message to QStash. Note the destination url is the URL from step 4. ```bash curl --request POST "https://qstash.upstash.io/v2/publish/https://urzdbfn4et56vzeasu3fpcynym0zerme.lambda-url.eu-west-1.on.aws" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d "{ \"hello\": \"world\"}" ``` ## Next Steps That's it, you have successfully created a secure AWS lambda function, that receives and verifies incoming webhooks from qstash. Learn more about publishing a message to qstash [here](/qstash/howto/publishing) # Cloudflare Workers Source: https://upstash.com/docs/qstash/quickstarts/cloudflare-workers This is a step by step guide on how to receive webhooks from QStash in your Cloudflare Worker. ### Project Setup We will use **C3 (create-cloudflare-cli)** command-line tool to create our functions. You can open a new terminal window and run C3 using the prompt below. ```shell npm npm create cloudflare@latest ``` ```shell yarn yarn create cloudflare@latest ``` This will install the `create-cloudflare` package, and lead you through setup. C3 will also install Wrangler in projects by default, which helps us testing and deploying the projects. ```text āžœ npm create cloudflare@latest Need to install the following packages: create-cloudflare@2.1.0 Ok to proceed? (y) y using create-cloudflare version 2.1.0 ā•­ Create an application with Cloudflare Step 1 of 3 │ ā”œ In which directory do you want to create your application? │ dir ./cloudflare_starter │ ā”œ What type of application do you want to create? │ type "Hello World" Worker │ ā”œ Do you want to use TypeScript? │ yes typescript │ ā”œ Copying files from "hello-world" template │ ā”œ Do you want to use TypeScript? │ yes typescript │ ā”œ Retrieving current workerd compatibility date │ compatibility date 2023-08-07 │ ā”œ Do you want to use git for version control? │ yes git │ ā•° Application created ``` We will also install the **Upstash QStash library**. ```bash npm install @upstash/qstash ``` ### 3. Use QStash in your handler First we import the library: ```ts src/index.ts import { Receiver } from "@upstash/qstash"; ``` Then we adjust the `Env` interface to include the `QSTASH_CURRENT_SIGNING_KEY` and `QSTASH_NEXT_SIGNING_KEY` environment variables. ```ts src/index.ts export interface Env { QSTASH_CURRENT_SIGNING_KEY: string; QSTASH_NEXT_SIGNING_KEY: string; } ``` And then we validate the signature in the `handler` function. First we create a new receiver and provide it with the signing keys. ```ts src/index.ts const receiver = new Receiver({ currentSigningKey: env.QSTASH_CURRENT_SIGNING_KEY, nextSigningKey: env.QSTASH_NEXT_SIGNING_KEY, }); ``` Then we verify the signature. ```ts src/index.ts const body = await request.text(); const isValid = receiver.verify({ signature: request.headers.get("Upstash-Signature")!, body, }); ``` The entire file looks like this now: ```ts src/index.ts import { Receiver } from "@upstash/qstash"; export interface Env { QSTASH_CURRENT_SIGNING_KEY: string; QSTASH_NEXT_SIGNING_KEY: string; } export default { async fetch( request: Request, env: Env, ctx: ExecutionContext ): Promise { const c = new Receiver({ currentSigningKey: env.QSTASH_CURRENT_SIGNING_KEY, nextSigningKey: env.QSTASH_NEXT_SIGNING_KEY, }); const body = await request.text(); const isValid = await c .verify({ signature: request.headers.get("Upstash-Signature")!, body, }) .catch((err) => { console.error(err); return false; }); if (!isValid) { return new Response("Invalid signature", { status: 401 }); } console.log("The signature was valid"); // do work here return new Response("Hello World!"); }, }; ``` ### Configure Credentials There are two methods for setting up the credentials for QStash. The recommended way is to use Cloudflare Upstash Integration. Alternatively, you can add the credentials manually. #### Using the Cloudflare Integration Access to the [Cloudflare Dashboard](https://dash.cloudflare.com) and login with the same account that you've used while setting up the Worker application. Then, navigate to **Workers & Pages > Overview** section on the sidebar. Here, you'll find your application listed. Clicking on the application will direct you to the application details page, where you can perform the integration process. Switch to the **Settings** tab in the application details, and proceed to **Integrations** section. You will see various Worker integrations listed. To proceed, click the **Add Integration** button associated with the QStash. On the Integration page, connect to your Upstash account. Then, select the related database from the dropdown menu. Finalize the process by pressing Save button. #### Setting up Manually Navigate to [Upstash Console](https://console.upstash.com) and copy/paste your QStash credentials to `wrangler.toml` as below. ```yaml [vars] QSTASH_URL="REPLACE_HERE" QSTASH_TOKEN="REPLACE_HERE" QSTASH_CURRENT_SIGNING_KEY="REPLACE_HERE" QSTASH_NEXT_SIGNING_KEY="REPLACE_HERE" ``` ### Test and Deploy You can test the function locally with `npx wrangler dev` Deploy your function to Cloudflare with `npx wrangler deploy` The endpoint of the function will be provided to you, once the deployment is done. ### Publish a message Open a different terminal and publish a message to QStash. Note the destination url is the same that was printed in the previous deploy step. ```bash curl --request POST "https://qstash.upstash.io/v2/publish/https://cloudflare-workers.upstash.workers.dev" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d "{ \"hello\": \"world\"}" ``` In the logs you should see something like this: ```bash $ npx wrangler tail ā›…ļø wrangler 2.0.17 -------------------- Retrieving cached values for account from node_modules/.cache/wrangler Successfully created tail, expires at 2022-07-11T21:11:36Z Connected to cloudflare-workers, waiting for logs... POST https://cloudflare-workers.upstash.workers.dev/ - Ok @ 7/11/2022, 5:13:19 PM (log) The signature was valid ``` ## Next Steps That's it, you have successfully created a secure Cloudflare Worker, that receives and verifies incoming webhooks from qstash. Learn more about publishing a message to qstash [here](/qstash/howto/publishing). You can find the source code [here](https://github.com/upstash/qstash-examples/tree/main/cloudflare-workers). # Deno Deploy Source: https://upstash.com/docs/qstash/quickstarts/deno-deploy [Source Code](https://github.com/upstash/qstash-examples/tree/main/deno-deploy) This is a step by step guide on how to receive webhooks from QStash in your Deno deploy project. ### 1. Create a new project Go to [https://dash.deno.com/projects](https://dash.deno.com/projects) and create a new playground project. ### 2. Edit the handler function Then paste the following code into the browser editor: ```ts import { serve } from "https://deno.land/std@0.142.0/http/server.ts"; import { Receiver } from "https://deno.land/x/upstash_qstash@v0.1.4/mod.ts"; serve(async (req: Request) => { const r = new Receiver({ currentSigningKey: Deno.env.get("QSTASH_CURRENT_SIGNING_KEY")!, nextSigningKey: Deno.env.get("QSTASH_NEXT_SIGNING_KEY")!, }); const isValid = await r .verify({ signature: req.headers.get("Upstash-Signature")!, body: await req.text(), }) .catch((err: Error) => { console.error(err); return false; }); if (!isValid) { return new Response("Invalid signature", { status: 401 }); } console.log("The signature was valid"); // do work return new Response("OK", { status: 200 }); }); ``` ### 3. Add your signing keys Click on the `settings` button at the top of the screen and then click `+ Add Variable` Get your current and next signing key from [Upstash](https://console.upstash.com/qstash) and then set them in deno deploy. ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/deno_deploy_env.png) ### 4. Deploy Simply click on `Save & Deploy` at the top of the screen. ### 5. Publish a message Make note of the url displayed in the top right. This is the public url of your project. ```bash curl --request POST "https://qstash.upstash.io/v2/publish/https://early-frog-33.deno.dev" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d "{ \"hello\": \"world\"}" ``` In the logs you should see something like this: ```basheurope-west3isolate start time: 2.21 ms Listening on http://localhost:8000/ The signature was valid ``` ## Next Steps That's it, you have successfully created a secure deno API, that receives and verifies incoming webhooks from qstash. Learn more about publishing a message to qstash [here](/qstash/howto/publishing) # Golang Source: https://upstash.com/docs/qstash/quickstarts/fly-io/go [Source Code](https://github.com/upstash/qstash-examples/tree/main/fly.io/go) This is a step by step guide on how to receive webhooks from QStash in your Golang application running on [fly.io](https://fly.io). ## 0. Prerequisites * [flyctl](https://fly.io/docs/getting-started/installing-flyctl/) - The fly.io CLI ## 1. Create a new project Let's create a new folder called `flyio-go` and initialize a new project. ```bash mkdir flyio-go cd flyio-go go mod init flyio-go ``` ## 2. Creating the main function In this example we will show how to receive a webhook from QStash and verify the signature using the popular [golang-jwt/jwt](https://github.com/golang-jwt/jwt) library. First, let's import everything we need: ```go package main import ( "crypto/sha256" "encoding/base64" "fmt" "github.com/golang-jwt/jwt/v4" "io" "net/http" "os" "time" ) ``` Next we create `main.go`. Ignore the `verify` function for now. We will add that next. In the handler we will prepare all necessary variables that we need for verification. This includes the signature and the signing keys. Then we try to verify the request using the current signing key and if that fails we will try the next one. If the signature could be verified, we can start processing the request. ```go func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() currentSigningKey := os.Getenv("QSTASH_CURRENT_SIGNING_KEY") nextSigningKey := os.Getenv("QSTASH_NEXT_SIGNING_KEY") tokenString := r.Header.Get("Upstash-Signature") body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } err = verify(body, tokenString, currentSigningKey) if err != nil { fmt.Printf("Unable to verify signature with current signing key: %v", err) err = verify(body, tokenString, nextSigningKey) } if err != nil { http.Error(w, err.Error(), http.StatusUnauthorized) return } // handle your business logic here w.WriteHeader(http.StatusOK) }) fmt.Println("listening on", port) err := http.ListenAndServe(":"+port, nil) if err != nil { panic(err) } } ``` The `verify` function will handle verification of the [JWT](https://jwt.io), that includes claims about the request. See [here](/qstash/features/security#claims). ```go func verify(body []byte, tokenString, signingKey string) error { token, err := jwt.Parse( tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } return []byte(signingKey), nil }) if err != nil { return err } claims, ok := token.Claims.(jwt.MapClaims) if !ok || !token.Valid { return fmt.Errorf("Invalid token") } if !claims.VerifyIssuer("Upstash", true) { return fmt.Errorf("invalid issuer") } if !claims.VerifyExpiresAt(time.Now().Unix(), true) { return fmt.Errorf("token has expired") } if !claims.VerifyNotBefore(time.Now().Unix(), true) { return fmt.Errorf("token is not valid yet") } bodyHash := sha256.Sum256(body) if claims["body"] != base64.URLEncoding.EncodeToString(bodyHash[:]) { return fmt.Errorf("body hash does not match") } return nil } ``` You can find the complete file [here](https://github.com/upstash/qstash-examples/blob/main/fly.io/go/main.go). That's it, now we can deploy our API and test it. ## 3. Create app on fly.io [Login](https://fly.io/docs/getting-started/log-in-to-fly/) with `flyctl` and then `flyctl launch` the new app. This will create the necessary `fly.toml` for us. It will ask you a bunch of questions. I chose all defaults here except for the last question. We do not want to deploy just yet. ```bash $ flyctl launch Creating app in /Users/andreasthomas/github/upstash/qstash-examples/fly.io/go Scanning source code Detected a Go app Using the following build configuration: Builder: paketobuildpacks/builder:base Buildpacks: gcr.io/paketo-buildpacks/go ? App Name (leave blank to use an auto-generated name): Automatically selected personal organization: Andreas Thomas ? Select region: fra (Frankfurt, Germany) Created app winer-cherry-9545 in organization personal Wrote config file fly.toml ? Would you like to setup a Postgresql database now? No ? Would you like to deploy now? No Your app is ready. Deploy with `flyctl deploy` ``` ## 4. Set Environment Variables Get your current and next signing key from the [Upstash Console](https://console.upstash.com/qstash) Then set them using `flyctl secrets set ...` ```bash flyctl secrets set QSTASH_CURRENT_SIGNING_KEY=... flyctl secrets set QSTASH_NEXT_SIGNING_KEY=... ``` ## 5. Deploy the app Fly.io made this step really simple. Just `flyctl deploy` and enjoy. ```bash flyctl deploy ``` ## 6. Publish a message Now you can publish a message to QStash. Note the destination url is basically your app name, if you are not sure what it is, you can go to [fly.io/dashboard](https://fly.io/dashboard) and find out. In my case the app is named "winter-cherry-9545" and the public url is "[https://winter-cherry-9545.fly.dev](https://winter-cherry-9545.fly.dev)". ```bash curl --request POST "https://qstash.upstash.io/v2/publish/https://winter-cherry-9545.fly.dev" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d "{ \"hello\": \"world\"}" ``` ## Next Steps That's it, you have successfully created a Go API hosted on fly.io, that receives and verifies incoming webhooks from qstash. Learn more about publishing a message to qstash [here](/qstash/howto/publishing) # Python on Vercel Source: https://upstash.com/docs/qstash/quickstarts/python-vercel ## Introduction This quickstart will guide you through setting up QStash to run a daily script to clean up your database. This is useful for testing and development environments where you want to reset the database every day. ## Prerequisites * Create an Upstash account and get your [QStash token](https://console.upstash.com/qstash) First, we'll create a new directory for our Python app. We'll call it `clean-db-cron`. The database we'll be using is Redis, so we'll need to install the `upstash_redis` package. ```bash mkdir clean-db-cron ``` ```bash cd clean-db-cron ``` ```bash pip install upstash-redis ``` Let's write the Python code to clean up the database. We'll use the `upstash_redis` package to connect to the database and delete all keys. ```python index.py from upstash_redis import Redis redis = Redis(url="https://YOUR_REDIS_URL", token="YOUR_TOKEN") def delete_all_entries(): keys = redis.keys("*") # Match all keys redis.delete(*keys) delete_all_entries() ``` Try running the code to see if it works. Your database keys should be deleted! In order to use QStash, we need to make the Python code into a public endpoint. There are many ways to do this such as using Flask, FastAPI, or Django. In this example, we'll use the Python `http.server` module to create a simple HTTP server. ```python api/index.py from http.server import BaseHTTPRequestHandler from upstash_redis import Redis redis = Redis(url="https://YOUR_REDIS_URL", token="YOUR_TOKEN") def delete_all_entries(): keys = redis.keys("*") # Match all keys redis.delete(*keys) class handler(BaseHTTPRequestHandler): def do_POST(self): delete_all_entries() self.send_response(200) self.end_headers() ``` For the purpose of this tutorial, I'll deploy the application to Vercel using the [Python Runtime](https://vercel.com/docs/functions/runtimes/python), but feel free to use any other hosting provider. There are many ways to [deploy to Vercel](https://vercel.com/docs/deployments/overview), but I'm going to use the Vercel CLI. ```bash npm install -g vercel ``` ```bash vercel ``` Once deployed, you can find the public URL in the dashboard. There are two ways we can go about configuring QStash. We can either use the QStash dashboard or the QStash API. In this example, it makes more sense to utilize the dashboard since we only need to set up a singular cronjob. However, you can imagine a scenario where you have a large number of cronjobs and you'd want to automate the process. In that case, you'd want to use the QStash Python SDK. To create the schedule, go to the [QStash dashboard](https://console.upstash.com/qstash) and enter the URL of the public endpoint you created. Then, set the type to schedule and change the `Upstash-Cron` header to run daily at a time of your choosing. ``` URL: https://your-vercel-app.vercel.app/api Type: Schedule Every: every day at midnight (feel free to customize) ``` QStash console scheduling Once you start the schedule, QStash will invoke the endpoint at the specified time. You can scroll down and verify the job has been created! If you have a use case where you need to automate the creation of jobs, you can use the SDK instead. ```python from qstash import QStash client = QStash("") client.schedule.create( destination="https://YOUR_URL.vercel.app/api", cron="0 12 * * *", ) ``` Now, go ahead and try it out for yourself! Try using some of the other features of QStash, such as [callbacks](/qstash/features/callbacks) and [URL Groups](/qstash/features/url-groups). # Next.js Source: https://upstash.com/docs/qstash/quickstarts/vercel-nextjs QStash is a robust message queue and task-scheduling service that integrates perfectly with Next.js. This guide will show you how to use QStash in your Next.js projects, including a quickstart and a complete example. ## Quickstart At its core, each QStash message contains two pieces of information: * URL (which endpoint to call) * Request body (e.g. IDs of items you want to process) The following endpoint could be used to upload an image and then asynchronously queue a processing task to optimize the image in the background. ```tsx upload-image/route.ts import { Client } from "@upstash/qstash" import { NextResponse } from "next/server" const client = new Client({ token: process.env.QSTASH_TOKEN! }) export const POST = async (req: Request) => { // Image uploading logic // šŸ‘‡ Once uploading is done, queue an image processing task const result = await client.publishJSON({ url: "https://your-api-endpoint.com/process-image", body: { imageId: "123" }, }) return NextResponse.json({ message: "Image queued for processing!", qstashMessageId: result.messageId, }) } ``` Note that the URL needs to be publicly available for QStash to call, either as a deployed project or by [developing with QStash locally](/qstash/howto/local-tunnel). Because QStash calls our image processing task, we get automatic retries whenever the API throws an error. These retries make our function very reliable. We also let the user know immediately that their image has been successfully queued. Now, let's **receive the QStash message** in our image processing endpoint: ```tsx process-image/route.ts import { verifySignatureAppRouter } from "@upstash/qstash/nextjs" // šŸ‘‡ Verify that this messages comes from QStash export const POST = verifySignatureAppRouter(async (req: Request) => { const body = await req.json() const { imageId } = body as { imageId: string } // Image processing logic, i.e. using sharp return new Response(`Image with id "${imageId}" processed successfully.`) }) ``` ```bash .env # Copy all three from your QStash dashboard QSTASH_TOKEN= QSTASH_CURRENT_SIGNING_KEY= QSTASH_NEXT_SIGNING_KEY= ``` Just like that, we set up a reliable and asynchronous image processing system in Next.js. The same logic works for email queues, reliable webhook processing, long-running report generations and many more. ## Example project * Create an Upstash account and get your [QStash token](https://console.upstash.com/qstash) * Node.js installed ```bash npx create-next-app@latest qstash-bg-job ``` ```bash cd qstash-bg-job ``` ```bash npm install @upstash/qstash ``` ```bash npm run dev ``` After removing the default content in `src/app/page.tsx`, let's create a simple UI to trigger the background job using a button. ```tsx src/app/page.tsx "use client" export default function Home() { return (
) } ``` Quickstart UI
We can use QStash to start a background job by calling the `publishJSON` method. In this example, we're using Next.js server actions, but you can also use route handlers. Since we don't have our public API endpoint yet, we can use [Request Catcher](https://requestcatcher.com/) to test the background job. This will eventually be replaced with our own API endpoint. ```ts src/app/actions.ts "use server" import { Client } from "@upstash/qstash" const qstashClient = new Client({ // Add your token to a .env file token: process.env.QSTASH_TOKEN!, }) export async function startBackgroundJob() { await qstashClient.publishJSON({ url: "https://firstqstashmessage.requestcatcher.com/test", body: { hello: "world", }, }) } ``` Now let's invoke the `startBackgroundJob` function when the button is clicked. ```tsx src/app/page.tsx "use client" import { startBackgroundJob } from "@/app/actions" export default function Home() { async function handleClick() { await startBackgroundJob() } return (
) } ``` To test the background job, click the button and check the Request Catcher for the incoming request. You can also head over to [Upstash Console](https://console.upstash.com/qstash) and go to the `Logs` tab where you can see your message activities.
Now that we know QStash is working, let's create our own endpoint to handle a background job. This is the endpoint that will be invoked by QStash. This job will be responsible for sending 10 requests, each with a 500ms delay. Since we're deploying to Vercel, we have to be cautious of the [time limit for serverless functions](https://vercel.com/docs/functions/runtimes#max-duration). ```ts src/app/api/long-task/route.ts export async function POST(request: Request) { const data = await request.json() for (let i = 0; i < 10; i++) { await fetch("https://firstqstashmessage.requestcatcher.com/test", { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, }) await new Promise((resolve) => setTimeout(resolve, 500)) } return Response.json({ success: true }) } ``` Now let's update our `startBackgroundJob` function to use our new endpoint. There's 1 problem: our endpoint is not public. We need to make it public so that QStash can call it. We have 2 options: 1. Deploy our application to a platform like Vercel and use the public URL. 2. Create a [local tunnel](/qstash/howto/local-tunnel) to test the endpoint locally. For the purpose, of this tutorial, I'll deploy the application to Vercel, but feel free to use a local tunnel if you prefer. There are many ways to [deploy to Vercel](https://vercel.com/docs/deployments/overview), but I'm going to use the Vercel CLI. ```bash npm install -g vercel ``` ```bash vercel ``` Once deployed, you can find the public URL in the Vercel dashboard. Now that we have a public URL, we can update the URL. ```ts src/app/actions.ts "use server" import { Client } from "@upstash/qstash" const qstashClient = new Client({ token: process.env.QSTASH_TOKEN!, }) export async function startBackgroundJob() { await qstashClient.publishJSON({ // Replace with your public URL url: "https://qstash-bg-job.vercel.app/api/long-task", body: { hello: "world", }, }) } ``` And voila! You've created a Next.js app that calls a long-running background job using QStash. QStash is a great way to handle background jobs, but it's important to remember that it's a public API. This means that anyone can call your endpoint. Make sure to add security measures to your endpoint to ensure that QStash is the sender of the request. Luckily, our SDK provides a way to verify the sender of the request. Make sure to get your signing keys from the QStash console and add them to your environment variables. The `verifySignatureAppRouter` will try to load `QSTASH_CURRENT_SIGNING_KEY` and `QSTASH_NEXT_SIGNING_KEY` from the environment. If one of them is missing, an error is thrown. ```ts src/app/api/long-task/route.ts import { verifySignatureAppRouter } from "@upstash/qstash/nextjs" async function handler(request: Request) { const data = await request.json() for (let i = 0; i < 10; i++) { await fetch("https://firstqstashmessage.requestcatcher.com/test", { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, }) await new Promise((resolve) => setTimeout(resolve, 500)) } return Response.json({ success: true }) } export const POST = verifySignatureAppRouter(handler) ``` Let's also add error catching to our action and a loading state to our UI. ```ts src/app/actions.ts "use server" import { Client } from "@upstash/qstash"; const qstashClient = new Client({ token: process.env.QSTASH_TOKEN!, }); export async function startBackgroundJob() { try { const response = await qstashClient.publishJSON({ "url": "https://qstash-bg-job.vercel.app/api/long-task", body: { "hello": "world" } }); return response.messageId; } catch (error) { console.error(error); return null; } } ``` ```tsx src/app/page.tsx "use client" import { startBackgroundJob } from "@/app/actions"; import { useState } from "react"; export default function Home() { const [loading, setLoading] = useState(false); const [msg, setMsg] = useState(""); async function handleClick() { setLoading(true); const messageId = await startBackgroundJob(); if (messageId) { setMsg(`Started job with ID ${messageId}`); } else { setMsg("Failed to start background job"); } setLoading(false); } return (
{loading &&
Loading...
} {msg &&

{msg}

}
); } ```
## Result We have now created a Next.js app that calls a long-running background job using QStash! Here's the app in action: Quickstart Result Gif We can also view the logs on Vercel and QStash Vercel Vercel Logs QStash Vercel Logs And the code for the 3 files we created: ```tsx src/app/page.tsx "use client" import { startBackgroundJob } from "@/app/actions"; import { useState } from "react"; export default function Home() { const [loading, setLoading] = useState(false); const [msg, setMsg] = useState(""); async function handleClick() { setLoading(true); const messageId = await startBackgroundJob(); if (messageId) { setMsg(`Started job with ID ${messageId}`); } else { setMsg("Failed to start background job"); } setLoading(false); } return (
{loading &&
Loading...
} {msg &&

{msg}

}
); } ``` ```ts src/app/actions.ts "use server" import { Client } from "@upstash/qstash"; const qstashClient = new Client({ token: process.env.QSTASH_TOKEN!, }); export async function startBackgroundJob() { try { const response = await qstashClient.publishJSON({ "url": "https://qstash-bg-job.vercel.app/api/long-task", body: { "hello": "world" } }); return response.messageId; } catch (error) { console.error(error); return null; } } ``` ```ts src/app/api/long-task/route.ts import { verifySignatureAppRouter } from "@upstash/qstash/nextjs" async function handler(request: Request) { const data = await request.json() for (let i = 0; i < 10; i++) { await fetch("https://firstqstashmessage.requestcatcher.com/test", { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" }, }) await new Promise((resolve) => setTimeout(resolve, 500)) } return Response.json({ success: true }) } export const POST = verifySignatureAppRouter(handler) ```
Now, go ahead and try it out for yourself! Try using some of the other features of QStash, like [schedules](/qstash/features/schedules), [callbacks](/qstash/features/callbacks), and [URL Groups](/qstash/features/url-groups). # Periodic Data Updates Source: https://upstash.com/docs/qstash/recipes/periodic-data-updates * Code: [Repository](https://github.com/upstash/qstash-examples/tree/main/periodic-data-updates) * App: [qstash-examples-periodic-data-updates.vercel.app](https://qstash-examples-periodic-data-updates.vercel.app) This recipe shows how to use QStash as a trigger for a Next.js api route, that fetches data from somewhere and stores it in your database. For the database we will use Redis because it's very simple to setup and is not really the main focus of this recipe. ## What will be build? Let's assume there is a 3rd party API that provides some data. One approach would be to just query the API whenever you or your users need it, however that might not work well if the API is slow, unavailable or rate limited. A better approach would be to continuously fetch fresh data from the API and store it in your database. Traditionally this would require a long running process, that would continuously call the API. With QStash you can do this inside your Next.js app and you don't need to worry about maintaining anything. For the purpose of this recipe we will build a simple app, that scrapes the current Bitcoin price from a public API, stores it in redis and then displays a chart in the browser. ## Setup If you don't have one already, create a new Next.js project with `npx create-next-app@latest --ts`. Then install the required packages ```bash npm install @upstash/qstash @upstash/redis ``` You can replace `@upstash/redis` with any kind of database client you want. ## Scraping the API Create a new serverless function in `/pages/api/cron.ts` ````ts import { NextApiRequest, NextApiResponse } from "next"; import { Redis } from "@upstash/redis"; import { verifySignature } from "@upstash/qstash/nextjs"; /** * You can use any database you want, in this case we use Redis */ const redis = Redis.fromEnv(); /** * Load the current bitcoin price in USD and store it in our database at the * current timestamp */ async function handler(_req: NextApiRequest, res: NextApiResponse) { try { /** * The API returns something like this: * ```json * { * "USD": { * "last": 123 * }, * ... * } * ``` */ const raw = await fetch("https://blockchain.info/ticker"); const prices = await raw.json(); const bitcoinPrice = prices["USD"]["last"] as number; /** * After we have loaded the current bitcoin price, we can store it in the * database together with the current time */ await redis.zadd("bitcoin-prices", { score: Date.now(), member: bitcoinPrice, }); res.send("OK"); } catch (err) { res.status(500).send(err); } finally { res.end(); } } /** * Wrap your handler with `verifySignature` to automatically reject all * requests that are not coming from Upstash. */ export default verifySignature(handler); /** * To verify the authenticity of the incoming request in the `verifySignature` * function, we need access to the raw request body. */ export const config = { api: { bodyParser: false, }, }; ```` ## Deploy to Vercel That's all we need to fetch fresh data. Let's deploy our app to Vercel. You can either push your code to a git repository and deploy it to Vercel, or you can deploy it directly from your local machine using the [vercel cli](https://vercel.com/docs/cli). For a more indepth tutorial on how to deploy to Vercel, check out this [quickstart](/qstash/quickstarts/vercel-nextjs#4-deploy-to-vercel). After you have deployed your app, it is time to add your secrets to your environment variables. ## Secrets Head over to [QStash](https://console.upstash.com/qstash) and copy the `QSTASH_CURRENT_SIGNING_KEY` and `QSTASH_NEXT_SIGNING_KEY` to vercel's environment variables. ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/vercel_env.png) If you are not using a custom database, you can quickly create a new [Redis database](https://console.upstash.com/redis). Afterwards copy the `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` to vercel. In the near future we will update our [Vercel integration](https://vercel.com/integrations/upstash) to do this for you. ## Redeploy To use the environment variables, you need to redeploy your app. Either with `npx vercel --prod` or in the UI. ## Create cron trigger in QStash The last part is to add the trigger in QStash. Go to [QStash](https://console.upstash.com/qstash) and create a new schedule. ![](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/qstash/schedule.png) Now we will call your api function whenever you schedule is triggered. ## Adding frontend UI This part is probably the least interesting and would require more dependencies for styling etc. Check out the [index.tsx](https://github.com/upstash/qstash-examples/blob/main/periodic-data-updates/pages/index.tsx) file, where we load the data from the database and display it in a chart. ## Hosted example You can find a running example of this recipe [here](https://qstash-examples-periodic-data-updates.vercel.app/). # DLQ Source: https://upstash.com/docs/qstash/sdks/py/examples/dlq You can run the async code by importing `AsyncQStash` from `qstash` and awaiting the methods. #### Get all messages with pagination using cursor Since the DLQ can have a large number of messages, they are paginated. You can go through the results using the `cursor`. ```python from qstash import QStash client = QStash("") all_messages = [] cursor = None while True: res = client.dlq.list(cursor=cursor) all_messages.extend(res.messages) cursor = res.cursor if cursor is None: break ``` #### Get a message from the DLQ ```python from qstash import QStash client = QStash("") msg = client.dlq.get("") ``` #### Delete a message from the DLQ ```python from qstash import QStash client = QStash("") client.dlq.delete("") ``` # Events Source: https://upstash.com/docs/qstash/sdks/py/examples/events You can run the async code by importing `AsyncQStash` from `qstash` and awaiting the methods. #### Get all events with pagination using cursor Since there can be a large number of events, they are paginated. You can go through the results using the `cursor`. ```python from qstash import QStash client = QStash("") all_events = [] cursor = None while True: res = client.event.list(cursor=cursor) all_events.extend(res.events) cursor = res.cursor if cursor is None: break ``` # Keys Source: https://upstash.com/docs/qstash/sdks/py/examples/keys You can run the async code by importing `AsyncQStash` from `qstash` and awaiting the methods. #### Retrieve your signing Keys ```python from qstash import QStash client = QStash("") signing_key = client.signing_key.get() print(signing_key.current, signing_key.next) ``` #### Rotate your signing Keys ```python from qstash import QStash client = QStash("") new_signing_key = client.signing_key.rotate() print(new_signing_key.current, new_signing_key.next) ``` # Messages Source: https://upstash.com/docs/qstash/sdks/py/examples/messages You can run the async code by importing `AsyncQStash` from `qstash` and awaiting the methods. Messages are removed from the database shortly after they're delivered, so you will not be able to retrieve a message after. This endpoint is intended to be used for accessing messages that are in the process of being delivered/retried. #### Retrieve a message ```python from qstash import QStash client = QStash("") msg = client.message.get("") ``` #### Cancel/delete a message ```python from qstash import QStash client = QStash("") client.message.cancel("") ``` #### Cancel messages in bulk Cancel many messages at once or cancel all messages ```python from qstash import QStash client = QStash("") # cancel more than one message client.message.cancel_many(["", ""]) # cancel all messages client.message.cancel_all() ``` # Overview Source: https://upstash.com/docs/qstash/sdks/py/examples/overview These are example usages of each method in the QStash SDK. You can also reference the [examples repo](https://github.com/upstash/qstash-py/tree/main/examples) and [API examples](/qstash/overall/apiexamples) for more. # Publish Source: https://upstash.com/docs/qstash/sdks/py/examples/publish You can run the async code by importing `AsyncQStash` from `qstash` and awaiting the methods. #### Publish to a URL with a 3 second delay and headers/body ```python from qstash import QStash client = QStash("") res = client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, headers={ "test-header": "test-value", }, delay="3s", ) print(res.message_id) ``` #### Publish to a URL group with a 3 second delay and headers/body You can make a URL group on the QStash console or using the [URL group API](/qstash/sdks/py/examples/url-groups) ```python from qstash import QStash client = QStash("") res = client.message.publish_json( url_group="my-url-group", body={ "hello": "world", }, headers={ "test-header": "test-value", }, delay="3s", ) # When publishing to a URL group, the response is an array of messages for each URL in the group print(res[0].message_id) ``` #### Publish a method with a callback URL [Callbacks](/qstash/features/callbacks) are useful for long running functions. Here, QStash will return the response of the publish request to the callback URL. We also change the `method` to `GET` in this use case so QStash will make a `GET` request to the `url`. The default is `POST`. ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, callback="https://my-callback...", failure_callback="https://my-failure-callback...", method="GET", ) ``` #### Configure the number of retries The max number of retries is based on your [QStash plan](https://upstash.com/pricing/qstash) ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, retries=1, ) ``` #### Publish HTML content instead of JSON ```python from qstash import QStash client = QStash("") client.message.publish( url="https://my-api...", body="

Hello World

", content_type="text/html", ) ``` #### Publish a message with [content-based-deduplication](/qstash/features/deduplication) ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, content_based_deduplication=True, ) ``` #### Publish a message with timeout Timeout value to use when calling a url ([See `Upstash-Timeout` in Publish Message page](/qstash/api/publish#request)) ```python from qstash import QStash client = QStash("") client.message.publish_json( url="https://my-api...", body={ "hello": "world", }, timeout="30s", ) ``` # Queues Source: https://upstash.com/docs/qstash/sdks/py/examples/queues #### Create a queue with parallelism ```python from qstash import QStash client = QStash("") queue_name = "upstash-queue" client.queue.upsert(queue_name, parallelism=2) print(client.queue.get(queue_name)) ``` #### Delete a queue ```python from qstash import QStash client = QStash("") queue_name = "upstash-queue" client.queue.delete(queue_name) ``` Resuming or creating a queue may take up to a minute. Therefore, it is not recommended to pause or delete a queue during critical operations. #### Pause/Resume a queue ```python from qstash import QStash client = QStash("") queue_name = "upstash-queue" client.queue.upsert(queue_name, parallelism=1) client.queue.pause(queue_name) queue = client.queue.get(queue_name) print(queue.paused) # prints True client.queue.resume(queue_name) ``` Resuming or creating a queue may take up to a minute. Therefore, it is not recommended to pause or delete a queue during critical operations. # Receiver Source: https://upstash.com/docs/qstash/sdks/py/examples/receiver When receiving a message from QStash, you should [verify the signature](/qstash/howto/signature). The QStash Python SDK provides a helper function for this. ```python from qstash import Receiver receiver = Receiver( current_signing_key="YOUR_CURRENT_SIGNING_KEY", next_signing_key="YOUR_NEXT_SIGNING_KEY", ) # ... in your request handler signature, body = req.headers["Upstash-Signature"], req.body receiver.verify( body=body, signature=signature, url="YOUR-SITE-URL", ) ``` # Schedules Source: https://upstash.com/docs/qstash/sdks/py/examples/schedules You can run the async code by importing `AsyncQStash` from `qstash` and awaiting the methods. #### Create a schedule that runs every 5 minutes ```python from qstash import QStash client = QStash("") schedule_id = client.schedule.create( destination="https://my-api...", cron="*/5 * * * *", ) print(schedule_id) ``` #### Create a schedule that runs every hour and sends the result to a [callback URL](/qstash/features/callbacks) ```python from qstash import QStash client = QStash("") client.schedule.create( destination="https://my-api...", cron="0 * * * *", callback="https://my-callback...", failure_callback="https://my-failure-callback...", ) ``` #### Create a schedule to a URL group that runs every minute ```python from qstash import QStash client = QStash("") client.schedule.create( destination="my-url-group", cron="0 * * * *", ) ``` #### Get a schedule by schedule id ```python from qstash import QStash client = QStash("") schedule = client.schedule.get("") print(schedule.cron) ``` #### List all schedules ```python from qstash import QStash client = QStash("") all_schedules = client.schedule.list() print(all_schedules) ``` #### Delete a schedule ```python from qstash import QStash client = QStash("") client.schedule.delete("") ``` #### Create a schedule with timeout Timeout value to use when calling a schedule URL ([See `Upstash-Timeout` in Create Schedule page](/qstash/api/schedules/create)). ```python from qstash import QStash client = QStash("") schedule_id = client.schedule.create( destination="https://my-api...", cron="*/5 * * * *", timeout="30s", ) print(schedule_id) ``` #### Pause/Resume a schedule ```python from qstash import QStash client = QStash("") schedule_id = "scd_1234" client.schedule.pause(schedule_id) schedule = client.schedule.get(schedule_id) print(schedule.paused) # prints True client.schedule.resume(schedule_id) ``` # URL Groups Source: https://upstash.com/docs/qstash/sdks/py/examples/url-groups You can run the async code by importing `AsyncQStash` from `qstash` and awaiting the methods. #### Create a URL group and add 2 endpoints ```python from qstash import QStash client = QStash("") client.url_group.upsert_endpoints( url_group="my-url-group", endpoints=[ {"url": "https://my-endpoint-1"}, {"url": "https://my-endpoint-2"}, ], ) ``` #### Get URL group by name ```python from qstash import QStash client = QStash("") url_group = client.url_group.get("my-url-group") print(url_group.name, url_group.endpoints) ``` #### List URL groups ```python from qstash import QStash client = QStash("") all_url_groups = client.url_group.list() for url_group in all_url_groups: print(url_group.name, url_group.endpoints) ``` #### Remove an endpoint from a URL group ```python from qstash import QStash client = QStash("") client.url_group.remove_endpoints( url_group="my-url-group", endpoints=[ {"url": "https://my-endpoint-1"}, ], ) ``` #### Delete a URL group ```python from qstash import QStash client = QStash("") client.url_group.delete("my-url-group") ``` # Getting Started Source: https://upstash.com/docs/qstash/sdks/py/gettingstarted ## Install ### PyPI ```bash pip install qstash ``` ## Get QStash token Follow the instructions [here](/qstash/overall/getstarted) to get your QStash token and signing keys. ## Usage #### Synchronous Client ```python from qstash import QStash client = QStash("") client.message.publish_json(...) ``` #### Asynchronous Client ```python import asyncio from qstash import AsyncQStash async def main(): client = AsyncQStash("") await client.message.publish_json(...) asyncio.run(main()) ``` #### RetryConfig You can configure the retry policy of the client by passing the configuration to the client constructor. Note: This isn for sending the request to QStash, not for the retry policy of QStash. The default number of retries is **5** and the default backoff function is `lambda retry_count: math.exp(retry_count) * 50`. You can also pass in `False` to disable retrying. ```python from qstash import QStash client = QStash( "", retry={ "retries": 3, "backoff": lambda retry_count: (2**retry_count) * 20, }, ) ``` # Overview Source: https://upstash.com/docs/qstash/sdks/py/overview `qstash` is an Python SDK for QStash, allowing for easy access to the QStash API. Using `qstash` you can: * Publish a message to a URL/URL group/API * Publish a message with a delay * Schedule a message to be published * Access logs for the messages that have been published * Create, read, update, or delete URL groups. * Read or remove messages from the [DLQ](/qstash/features/dlq) * Read or cancel messages * Verify the signature of a message You can find the Github Repository [here](https://github.com/upstash/qstash-py). # DLQ Source: https://upstash.com/docs/qstash/sdks/ts/examples/dlq #### Get all messages with pagination using cursor Since the DLQ can have a large number of messages, they are paginated. You can go through the results using the `cursor`. ```typescript import { Client } from "@upstash/qstash"; const client = new Client(""); const dlq = client.dlq; const all_messages = []; let cursor = null; while (true) { const res = await dlq.listMessages({ cursor }); all_messages.push(...res.messages); cursor = res.cursor; if (!cursor) { break; } } ``` #### Delete a message from the DLQ ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const dlq = client.dlq; await dlq.delete("dlqId"); ``` # Logs Source: https://upstash.com/docs/qstash/sdks/ts/examples/logs #### Get all logs with pagination using cursor Since there can be a large number of logs, they are paginated. You can go through the results using the `cursor`. ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const logs = []; let cursor = null; while (true) { const res = await client.logs({ cursor }); logs.push(...res.logs); cursor = res.cursor; if (!cursor) { break; } } ``` #### Filter logs by state and only return the first 50. More filters can be found in the [API Reference](/qstash/api/events/list). ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.logs({ filter: { state: "DELIVERED", count: 50 } }); ``` # Messages Source: https://upstash.com/docs/qstash/sdks/ts/examples/messages Messages are removed from the database shortly after they're delivered, so you will not be able to retrieve a message after. This endpoint is intended to be used for accessing messages that are in the process of being delivered/retried. #### Retrieve a message ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const messages = client.messages const msg = await messages.get("msgId"); ``` #### Cancel/delete a message ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const messages = client.messages const msg = await messages.delete("msgId"); ``` #### Cancel messages in bulk Cancel many messages at once or cancel all messages ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); // deleting two messages at once await client.messages.deleteMany([ "message-id-1", "message-id-2", ]) // deleting all messages await client.messages.deleteAll() ``` # Overview Source: https://upstash.com/docs/qstash/sdks/ts/examples/overview These are example usages of each method in the QStash SDK. You can also reference the [examples repo](https://github.com/upstash/sdk-qstash-ts/tree/main/examples) and [API examples](/qstash/overall/apiexamples) for more. # Publish Source: https://upstash.com/docs/qstash/sdks/ts/examples/publish #### Publish to a URL with a 3 second delay and headers/body ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, headers: { "test-header": "test-value" }, delay: "3s", }); ``` #### Publish to a URL group with a 3 second delay and headers/body You create URL group on the QStash console or using the [URL Group API](/qstash/sdks/ts/examples/url-groups#create-a-url-group-and-add-2-endpoints) ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ urlGroup: "my-url-group", body: { hello: "world" }, headers: { "test-header": "test-value" }, delay: "3s", }); // When publishing to a URL Group, the response is an array of messages for each URL in the URL Group console.log(res[0].messageId); ``` #### Publish a method with a callback URL [Callbacks](/qstash/features/callbacks) are useful for long running functions. Here, QStash will return the response of the publish request to the callback URL. We also change the `method` to `GET` in this use case so QStash will make a `GET` request to the `url`. The default is `POST`. ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, callback: "https://my-callback...", failureCallback: "https://my-failure-callback...", method: "GET", }); ``` #### Configure the number of retries The max number of retries is based on your [QStash plan](https://upstash.com/pricing/qstash) ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, retries: 1, }); ``` #### Publish HTML content instead of JSON ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publish({ url: "https://my-api...", body: "

Hello World

", headers: { "Content-Type": "text/html", }, }); ``` #### Publish a message with [content-based-deduplication](/qstash/features/deduplication) ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, contentBasedDeduplication: true, }); ``` #### Publish a message with timeout Timeout value in seconds to use when calling a url ([See `Upstash-Timeout` in Publish Message page](/qstash/api/publish#request)) ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.publishJSON({ url: "https://my-api...", body: { hello: "world" }, timeout: "30s" // 30 seconds timeout }); ``` # Queues Source: https://upstash.com/docs/qstash/sdks/ts/examples/queues #### Create a queue with parallelism 2 ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const queueName = "upstash-queue"; await client.queue({ queueName }).upsert({ parallelism: 2 }); const queueDetails = await client.queue({ queueName }).get(); ``` #### Delete Queue ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const queueName = "upstash-queue"; await client.queue({ queueName: queueName }).delete(); ``` Resuming or creating a queue may take up to a minute. Therefore, it is not recommended to pause or delete a queue during critical operations. #### Pause/Resume a queue ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const name = "upstash-pause-resume-queue"; const queue = client.queue({ queueName: name }); await queue.upsert({ parallelism: 1 }); // pause queue await queue.pause(); const queueInfo = await queue.get(); console.log(queueInfo.paused); // prints true // resume queue await queue.resume(); ``` Resuming or creating a queue may take up to a minute. Therefore, it is not recommended to pause or delete a queue during critical operations. # Receiver Source: https://upstash.com/docs/qstash/sdks/ts/examples/receiver When receiving a message from QStash, you should [verify the signature](/qstash/howto/signature). The QStash Typescript SDK provides a helper function for this. ```typescript import { Receiver } from "@upstash/qstash"; const receiver = new Receiver({ currentSigningKey: "YOUR_CURRENT_SIGNING_KEY", nextSigningKey: "YOUR_NEXT_SIGNING_KEY", }); // ... in your request handler const signature = req.headers["Upstash-Signature"]; const body = req.body; const isValid = receiver.verify({ body, signature, url: "YOUR-SITE-URL", }); ``` # Schedules Source: https://upstash.com/docs/qstash/sdks/ts/examples/schedules #### Create a schedule that runs every 5 minutes ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "https://my-api...", cron: "*/5 * * * *", }); ``` #### Create a schedule that runs every hour and sends the result to a [callback URL](/qstash/features/callbacks) ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "https://my-api...", cron: "0 * * * *", callback: "https://my-callback...", failureCallback: "https://my-failure-callback...", }); ``` #### Create a schedule to a URL Group that runs every minute ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "my-url-group", cron: "* * * * *", }); ``` #### Get a schedule by schedule id ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const res = await client.schedules.get("scheduleId"); console.log(res.cron); ``` #### List all schedules ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const allSchedules = await client.schedules.list(); console.log(allSchedules); ``` #### Create/overwrite a schedule with a user chosen schedule id Note that if a schedule exists with the same id, the old one will be discarded and new schedule will be used. ```typescript Typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ destination: "https://example.com", scheduleId: "USER_PROVIDED_SCHEDULE_ID", cron: "* * * * *", }); ``` #### Delete a schedule ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.delete("scheduleId"); ``` #### Create a schedule with timeout Timeout value in seconds to use when calling a schedule URL ([See `Upstash-Timeout` in Create Schedule page](/qstash/api/schedules/create)). ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); await client.schedules.create({ url: "https://my-api...", cron: "* * * * *", timeout: "30" // 30 seconds timeout }); ``` #### Pause/Resume a schedule ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const scheduleId = "my-schedule" // pause schedule await client.schedules.pause({ schedule: scheduleId }); // check if paused const result = await client.schedules.get(scheduleId); console.log(getResult.isPaused) // prints true // resume schedule await client.schedules.resume({ schedule: scheduleId }); ``` # URL Groups Source: https://upstash.com/docs/qstash/sdks/ts/examples/url-groups #### Create a URL Group and add 2 endpoints ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const urlGroups = client.urlGroups; await urlGroups.addEndpoints({ name: "url_group_name", endpoints: [ { url: "https://my-endpoint-1" }, { url: "https://my-endpoint-2" }, ], }); ``` #### Get URL Group by name ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const urlGroups = client.urlGroups; const urlGroup = await urlGroups.get("urlGroupName"); console.log(urlGroup.name, urlGroup.endpoints); ``` #### List URL Groups ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const allUrlGroups = await client.urlGroups.list(); for (const urlGroup of allUrlGroups) { console.log(urlGroup.name, urlGroup.endpoints); } ``` #### Remove an endpoint from a URL Group ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const urlGroups = client.urlGroups; await urlGroups.removeEndpoints({ name: "urlGroupName", endpoints: [{ url: "https://my-endpoint-1" }], }); ``` #### Delete a URL Group ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "" }); const urlGroups = client.urlGroups; await urlGroups.delete("urlGroupName"); ``` # Getting Started Source: https://upstash.com/docs/qstash/sdks/ts/gettingstarted ## Install ### NPM ```bash npm install @upstash/qstash ``` ## Get QStash token Follow the instructions [here](/qstash/overall/getstarted) to get your QStash token and signing keys. ## Usage ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "", }); ``` #### RetryConfig You can configure the retry policy of the client by passing the configuration to the client constructor. Note: This is for sending the request to QStash, not for the retry policy of QStash. The default number of attempts is **6** and the default backoff function is `(retry_count) => (Math.exp(retry_count) * 50)`. You can also pass in `false` to disable retrying. ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ token: "", retry: { retries: 3, backoff: retry_count => 2 ** retry_count * 20, }, }); ``` # Overview Source: https://upstash.com/docs/qstash/sdks/ts/overview `@upstash/qstash` is a Typescript SDK for QStash, allowing for easy access to the QStash API. Using `@upstash/qstash` you can: * Publish a message to a URL/URL Group * Publish a message with a delay * Schedule a message to be published * Access logs for the messages that have been published * Create, read, update, or delete URL groups. * Read or remove messages from the [DLQ](/qstash/features/dlq) * Read or cancel messages * Verify the signature of a message You can find the Github Repository [here](https://github.com/upstash/sdk-qstash-ts). # Examples Index Source: https://upstash.com/docs/redis/examples List of all Upstash Examples TODO: fahreddin import TagFilters from "../../src/components/Filter.js" SvelteKit TODO App with Redis Serverless Redis Caching for Strapi To-Do List with Blitz.js & Redis Slackbot with AWS Chalice and Upstash Redis Using Render with Redis Slackbot with Vercel and Upstash Redis Slackbot with Vercel and Upstash Redis Remix on Cloudflare with Upstash Redis Remix TODO App with Redis Global Cache for Netlify Graph with Upstash Redis Next.js Authentication with NextAuth and Serverless Redis Building a Survey App with Upstash Redis and Next.js Building React Native Apps Backed by AWS Lambda and Serverless Redis Using Upstash Redis with Remix Using Upstash Redis as a Session Store for Remix Building a Serverless Notification API for Your Web Application with Redis Build Stateful Applications with AWS App Runner and Serverless Redis Session Management on Google Cloud Run with Serverless Redis Use Redis in Cloudflare Workers Use Redis in Fastly Compute Build a Leaderboard API at Edge Using Cloudflare Workers and Redis Job Processing and Event Queue with Serverless Redis AWS Lambda Rate Limiting with Serverless Redis Build a Serverless Histogram API with Redis Autocomplete API with Serverless Redis Roadmap Voting App with Serverless Redis Building a Survey App with Upstash Redis only Serverless Redis on Google Cloud Functions Using Serverless Framework Using AWS SAM Deploy a Serverless API with AWS CDK and AWS Lambda Express Session with Serverless Redis Next.js with Redis Nuxt.js with Redis Serverless API with Java and Redis Serverless Golang API with Redis Serverless Python API with Redis Serverless Redisson Building SvelteKit Applications with Serverless Redis Build Your Own Waiting Room for Your Website with Cloudflare Workers and Serverless Redis Fullstack Serverless App with Flutter, Serverless Framework and Upstash(REDIS) - PART 1 Getting Started with Next.js Edge Functions Waiting Room for Your Next.js App Using Edge Functions Serverless Battleground - DynamoDB vs Firestore vs MongoDB vs Cassandra vs Redis vs FaunaDB Stateful AWS Lambda with Redis REST Pipeline REST API on Serverless Redis The Most Minimalist Next.js TODO App Implement IP Allow/Deny List at Edge with Cloudflare Workers and Upstash Redis Redis @ Edge with Cloudflare Workers Using Serverless Redis with Next.js Building a Cache with Upstash Redis in Next.js Vercel Edge Function URL Shortener with Upstash Redis Adding Feature Flags to Next.js (Upstash Redis, SWR, Hooks) Rate Limiting Your Serverless Functions with Upstash Redis Create a React Scoreboard with Upstash Redis Upstash on AWS Lambda Using Golang IP Address Allow/Deny with Cloudflare Workers and Upstash Redis Edge Functions Explained with Kelsey Hightower and Lee Robinson - (Next.js Conf 2021) Elixir with Redis # Auto Upgrade Source: https://upstash.com/docs/redis/features/auto-upgrade By default, Upstash will apply usage limits based on your current plan. When you reach these limits, behavior depends on the specific limit type - bandwidth limits will stop your traffic, while storage limits will reject new write operations. However, Upstash offers an Auto Upgrade feature that automatically upgrades your database to the next higher plan when you reach your usage limits, ensuring uninterrupted service. Auto Upgrade is particularly useful for applications with fluctuating or growing workloads, as it prevents service disruptions during high-traffic periods or when your data storage needs expand beyond your current plan. This feature allows your database to automatically scale with your application's demands without requiring manual intervention. ## How Auto Upgrade Works When enabled: * For **bandwidth limits**: Instead of stopping your traffic when you reach the bandwidth limit, your database will automatically upgrade to the next plan to accommodate the increased traffic. * For **storage limits**: Instead of rejecting write operations when you reach maximum data size, your database will upgrade to a plan with larger storage capacity. ## Managing Auto Upgrade * You can enable Auto Upgrade by checking the Auto Upgrade checkbox while creating a new database: * Or for an existing database by clicking Enable in the Configuration/Auto Upgrade box in the database details page: # Backup/Restore Source: https://upstash.com/docs/redis/features/backup You can create a manual backup of your database and restore that backup to any of your databases. Both backup and restore operations require that your database is in one of the AWS regions. Additionally, you can utilize the daily backup feature to automatically create backups of your database on a daily basis. ### Create A Manual Backup To create a manual backup of your database: * Go to the database details page and navigate to the `Backups` tab * Click on the `Backup` button and fill in a name for your backup. **Your backup name must be unique.** * Then click on the `Create` button. During the process of creating a backup for your database, it is important to note that your database will be temporarily locked, which means these operations will be unavailable during this time: * Create Database Backup * Enable TLS * Move Database to Team * Restore Database Backup * Update Eviction * Update Password * Delete Database ### Restore A Backup To restore a backup that was created from your current database, follow the steps below: * Go to the database details page and navigate to the `Backups` tab * Click on the `Restore` button next to the backup record listed. * Click on `Restore`. **Be aware of the fact that your target database will be flushed with this operation.** ### Restore A Backup From Another Database To restore a backup that was created from one of your databases other than the current one, follow the steps below: * Go to the database details page and navigate to the `Backups` tab * Click on the `Restore...` button * Select the source database, referring to the database from which the backup was generated. * Select the backup record that you want to restore to the current database. * Click on `Start Restore`. **Be aware of the fact that your target database will be flushed with this operation.** ### Enable Daily Automated Backup To enable daily automated backup for your database: * Go to the database details page and navigate to the `Backups` tab * Enable the switch next to the `Daily Backup` * Click on `Enable` ### Disable Daily Automated Backup To disable the daily automated backup for your database, please follow the steps below: * Go to the database details page and navigate to the `Backups` tab * Disable the switch next to the `Daily Backup` * Click on `Disable` # Consistency Source: https://upstash.com/docs/redis/features/consistency Upstash utilizes a leader-based replication mechanism. Under this mechanism, each key is assigned to a leader replica, which is responsible for handling write operations on that key. The remaining replicas serve as backups to the leader. When a write operation is performed on a key, it is initially processed by the leader replica and then asynchronously propagated to the backup replicas. This ensures that data consistency is maintained across the replicas. Reads can be performed from any replica. Each replica employs a failure detector to track liveness of the leader replica. When the leader replica fails for a reason, remaining replicas start a new leader election round and elect a new leader. This is the only unavailability window for the cluster where *write* your requests can be blocked for a short period of time. Also in case of cluster wide failures like network partitioning (split brain); periodically running anti entropy jobs resolve the conflicts using `Last-Writer-Wins` algorithm and converge the replicas to the same state. This model gives a better write consistency and read scalability but can provide only **Eventual Consistency**. Additionally you can achieve **Causal Consistency** (`Read-Your-Writes`, `Monotonic-Reads`, `Monotonic-Writes` and `Writes-Follow-Reads` guarantees) for a single Redis connection. (A TCP connection forms a session between client and server). Checkout [Read Your Writes](/redis/howto/readyourwrites) for more details on how to achieve RYW consistency. Checkout [Replication](/redis/features/replication) for more details on Replication mechanism. Previously, Upstash supported `Strong Consistency` mode for the single region databases. We decided to deprecate this feature because its effect on latency started to conflict with the performance expectations of Redis use cases. Also we are gradually moving to **CRDT** based Redis data structures, which will provide `Strong Eventual Consistency`. # Durable Storage Source: https://upstash.com/docs/redis/features/durability This article explains the persistence provided by Upstash databases. In Upstash, persistence is always enabled, setting it apart from other Redis offerings. Every write operation is consistently stored in both memory and the block storage provided by cloud providers, such as AWS's EBS. This dual storage approach ensures data durability. Read operations are optimized to first check if the data exists in memory, facilitating faster access. If the data is not in memory, it is retrieved from disk. This combination of memory and disk storage in Upstash guarantees reliable data access and maintains data integrity, even during system restarts or failures. ### Multi Tier Storage Upstash keeps your data both in memory and disk. This design provides: * Data safety with persistent storage * Low latency with in memory access * Price flexibility by using memory only for active data In Upstash, an entry in memory is evicted if it remains idle, meaning it has not been accessed for an extended period. It's important to note that eviction does not result in data loss since the entry is still stored in the block storage. When a read operation occurs for an evicted entry, it is efficiently reloaded from the block storage back into memory, ensuring fast access to the data. This eviction mechanism in Upstash optimizes memory usage by prioritizing frequently accessed data while maintaining the ability to retrieve less frequently accessed data when needed. Definitely, yes. Some users are worried that Redis data will be lost when a server crashes. This is not the case for Upstash thanks to Durable Storage. Data is reloaded to memory from block storage in case of a server crash. Moreover, except for the free tier, all paid tier databases provide extra redundancy by replicating data to multiple instances. # Eviction Source: https://upstash.com/docs/redis/features/eviction By default eviction is disabled, and Upstash Redis will reject write operations once the maximum data size limit has been reached. However, if you are utilizing Upstash Redis as a cache, you have the option to enable eviction. Enabling eviction allows older data to be automatically removed from the cache (including Durable Storage) when the maximum size limit is reached. This ensures that the cache remains within the allocated size and can make room for new data to be stored. Enabling eviction is particularly useful when the cache is intended to store frequently changing or temporary data, allowing the cache to adapt to evolving data needs while maintaining optimal performance. * You can enable eviction by checking **Eviction** checkbox while creating a new database: * Or for an existing database by clicking **Enable** in Configuration/Eviction box in the database details page: Upstash currently uses a single eviction algorithm, called **optimistic-volatile**, which is a combination of *volatile-random* and *allkeys-random* eviction policies available in [the original Redis](https://redis.io/docs/manual/eviction/#eviction-policies). Initially, Upstash employs random sampling to select keys for eviction, giving priority to keys marked with a TTL (expire field). If there is a shortage of volatile keys or they are insufficient to create space, additional non-volatile keys are randomly chosen for eviction. In future releases, Upstash plans to introduce more eviction policies, offering users a wider range of options to customize the eviction behavior according to their specific needs. # Global Database Source: https://upstash.com/docs/redis/features/globaldatabase In the global database, the replicas are distributed across multiple regions around the world. The clients are routed to the nearest region. This helps with minimizing latency for use cases where users can be anywhere in the world. ### Primary Region and Read Regions The Upstash Global database is structured with a Primary Region and multiple Read Regions. When a write command is issued, it is initially sent and processed at the Primary Region. The write operation is then replicated to all the Read Regions, ensuring data consistency across the database. On the other hand, when a read command is executed, it is directed to the nearest Read Region to optimize response time. By leveraging the Global database's distributed architecture, read operations can be performed with reduced latency, as data retrieval occurs from the closest available Read Region. The Global database's design thus aids in minimizing read operation latency by efficiently distributing data across multiple regions and enabling requests to be processed from the nearest Read Region. User selects a single primary region and multiple read regions. For the best performance, you should select the primary region in the same location where your writes happen. Select the read regions where your clients that read the Redis located. You may have your database with a single primary region but no read regions which would be practically same with a single region (regional) database. You can add or remove regions on a running Redis database. Here the list of regions currently supported: * AWS US-East-1 North Virginia * AWS US-East-2 Ohio * AWS US-West-1 North California * AWS US-West-2 Oregon * AWS EU-West-1 Ireland * AWS EU-West-2 London * AWS EU-Central-1 Frankfurt * AWS AP-South-1 Mumbai * AWS AP-SouthEast-1 Singapore * AWS AP-SouthEast-2 Sydney * AWS AP-NorthEast-1 Japan * AWS SA-East-1 SĆ£o Paulo In our internal tests, we see the following latencies (99th percentile): * Read latency from the same region \<1ms * Write latency from the same region \<5ms * Read/write latency from the same continent \<50ms ### Architecture In the multi region architecture, each key is owned by a primary replica which is located at the region that you choose as primary region. Read replicas become the backups of the primary for the related keys. The primary replica processes the writes, then propagates them to the read replicas. Read requests are processed by all replicas, this means you can read a value from any of the replicas. This model gives a better write consistency and read scalability. Each replica employs a failure detector to track the liveness of the primary replica. When the primary replica fails for a reason, read replicas start a new leader election round and elect a new leader (primary). This is the only unavailability window for the cluster where your requests can be blocked for a short period of time. Global Database is designed to optimize the latency of READ operations. It may not be a good choice if your use case is WRITE heavy. ### Use Cases * **Edge functions:** Edge computing (Cloudflare workers, Fastly Compute) is becoming a popular way of building globally fast applications. But there are limited data solutions accessible from edge functions. Upstash Global Database is accessible from Edge functions with the REST API. Low latency from all edge locations makes it a perfect solution for Edge functions * Multi region serverless architectures: You can run your AWS Lambda function in multiple regions to lower global latency. Vercel/Netlify functions can be run in different regions. Upstash Global database provides low latency data wherever your serverless functions are. * Web/mobile use cases where you need low latency globally. Thanks to the read only REST API, you can access Redis from your web/mobile application directly. In such a case, Global Database will help to lower the latency as you can expect the clients from anywhere. ### High Availability and Disaster Recovery Although the main motivation behind the Global Database is to provide low latency; it also makes your database resilient to region wide failures. When a region is not available, your requests are routed to another region; so your database remains available. ### Consistency Global Database is an eventually consistent database. The write request returns after the primary replica processes the operation. Write operation is replicated to read replicas asynchronously. Read requests can be served by any replica, which gives better horizontal scalability but also means a read request may return a stale value while a write operation for the same key is being propagated to read replicas. In case of cluster wide failures like network partitioning (split brain); periodically running anti entropy jobs resolve the conflicts using LWW algorithms and converge the replicas to the same state. ### Upgrade from Regional to Global Currently, we do not support auto-upgrade from regional to global database. You can export data from your old database and import into the global database. ### Pricing Global Database charges \$0.2 per 100K commands. The write commands are replicated to all read regions in addition to primary region so the replications are counted as commands. For example, if you have 1 primary 1 read region, 100K writes will cost \$0.4 (\$0.2 x 2). You can use Global Database in the free tier too. Free usage is limited with max one read region. # Replication Source: https://upstash.com/docs/redis/features/replication Replication is enabled for all paid Upstash databases. The data is replicated to multiple instances. Replication provides you high availability and better scalability. ### High Availability Replication makes your database resilient to failures because even one of the replicas is not available, your database continues to work. There are two types of replicas in Upstash Redis: primary replicas and read replicas. Primary replicas handle both reads and writes, while read replicas are used only for reads. In all subscription plans, primary replicas are highly available with multiple replicas to ensure that even if one fails, your database continues to function. If a read replica fails, your database remains operational, and you can still read from the primary replicas, though with higher latency. When [Prod Pack](https://upstash.com/docs/redis/overall/enterprise#prod-pack-features) is enabled, read replicas are also highly available. This ensures that if one read replica fails, you can read from another read replica in the same region without any additional latency. ### Better Scalability In a replicated database, your requests are evenly distributed among the replicas using a round-robin approach. As your throughput requirements grow, additional replicas can be added to the cluster to handle the increased workload and maintain high performance. This scalability feature ensures that your database can effectively meet the demands of high throughput scenarios. ### Architecture We use the single leader replication model. Each key is owned by a leader replica and other replicas become the backups of the leader. Writes on a key are processed by the leader replica first then propagated to backup replicas. Reads can be performed from any replica. This model gives a better write consistency and read scalability. ### Consistency Each replica in the cluster utilizes a failure detector to monitor the status of the leader replica. In the event that the leader replica fails, the remaining replicas initiate a new leader election process to select a new leader. During this leader election round, which is the only unavailability window for the cluster, there may be a short period of time where your requests can be temporarily blocked. However, once a new leader is elected, normal operations resume, ensuring the continued availability of the cluster. This mechanism ensures that any potential unavailability caused by leader failure is minimized, and the cluster can quickly recover and resume processing requests. Checkout [Read Your Writes](/redis/howto/readyourwrites) for more details on how to achieve RYW consistency. # REST API Source: https://upstash.com/docs/redis/features/restapi REST API enables you to access your Upstash database using REST. ## Get Started If you do not have a database already, follow [these steps](../overall/getstarted) to create one. In the database details section of the [Upstash Console](https://console.upstash.com), click the `REST API` button. Copy the REST URL and the authentication token. Send an HTTP GET request to the provided URL by adding an `Authorization: Bearer $TOKEN` header. ```shell curl https://us1-merry-cat-32748.upstash.io/set/foo/bar \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" ``` The above script executes a `SET foo bar` command. It will return a JSON response: ```json { "result": "OK" } ``` You can also set the token as `_token` request parameter as below: ```shell curl https://us1-merry-cat-32748.upstash.io/set/foo/bar?_token=2553feg6a2d9842h2a0gcdb5f8efe9934 ``` ## API Semantics Upstash REST API follows the same convention with [Redis Protocol](https://redis.io/commands). Give the command name and parameters in the same order as Redis protocol by separating them with a `/`. ```shell curl REST_URL/COMMAND/arg1/arg2/../argN ``` Here are some examples: * `SET foo bar` -> `REST_URL/set/foo/bar` * `SET foo bar EX 100` -> `REST_URL/set/foo/bar/EX/100` * `GET foo` -> `REST_URL/get/foo` * `MGET foo1 foo2 foo3` -> `REST_URL/mget/foo1/foo2/foo3` * `HGET employee:23381 salary` -> `REST_URL/hget/employee:23381/salary` * `ZADD teams 100 team-x 90 team-y` -> `REST_URL/zadd/teams/100/team-x/90/team-y` #### JSON or Binary Value To post a JSON or a binary value, you can use an HTTP POST request and set value as the request body: ```shell curl -X POST -d '$VALUE' https://us1-merry-cat-32748.upstash.io/set/foo \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" ``` In the example above, `$VALUE` sent in request body is appended to the command as `REST_URL/set/foo/$VALUE`. Please note that when making a POST request to the Upstash REST API, the request body is appended as the last parameter of the Redis command. If there are additional parameters in the Redis command after the value, you should include them as query parameters in the request: ```shell curl -X POST -d '$VALUE' https://us1-merry-cat-32748.upstash.io/set/foo?EX=100 \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" ``` Above command is equivalent to `REST_URL/set/foo/$VALUE/EX/100`. #### POST Command in Body Alternatively, you can send the whole command in the request body as a single JSON array. Array's first element must be the command name and command parameters should be appended next to each other in the same order as Redis protocol. ```shell curl -X POST -d '[COMMAND, ARG1, ARG2,.., ARGN]' REST_URL ``` For example, Redis command `SET foo bar EX 100` can be sent inside the request body as: ```shell curl -X POST -d '["SET", "foo", "bar", "EX", 100]' https://us1-merry-cat-32748.upstash.io \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" ``` ## HTTP Codes * `200 OK`: When request is accepted and successfully executed. * `400 Bad Request`: When there's a syntax error, an invalid/unsupported command is sent or command execution fails. * `401 Unauthorized`: When authentication fails; auth token is missing or invalid. * `405 Method Not Allowed`: When an unsupported HTTP method is used. Only `HEAD`, `GET`, `POST` and `PUT` methods are allowed. ## Response REST API returns a JSON response by default. When command execution is successful, response JSON will have a single `result` field and its value will contain the Redis response. It can be either; * a `null` value ```json { "result": null } ``` * an integer ```json { "result": 137 } ``` * a string ```json { "result": "value" } ``` * an array value: ```json { "result": ["value1", null, "value2"] } ``` If command is rejected or fails, response JSON will have a single `error` field with a string value explaining the failure: ```json {"error":"WRONGPASS invalid password"} {"error":"ERR wrong number of arguments for 'get' command"} ``` ### Base64 Encoded Responses If the response contains an invalid utf-8 character, it will be replaced with a ļæ½ (Replacement character U+FFFD). This can happen when you are using binary operations like `BITOP NOT` etc. If you prefer the raw response in base64 format, you can achieve this by setting the `Upstash-Encoding` header to `base64`. In this case, all strings in the response will be base64 encoded, except for the "OK" response. ```shell curl https://us1-merry-cat-32748.upstash.io/SET/foo/bar \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -H "Upstash-Encoding: base64" # {"result":"OK"} curl https://us1-merry-cat-32748.upstash.io/GET/foo \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -H "Upstash-Encoding: base64" # {"result":"YmFy"} ``` ### RESP2 Format Responses REST API returns a JSON response by default and the response content type is set to `application/json`. If you prefer the binary response in RESP2 format, you can achieve this by setting the `Upstash-Response-Format` header to `resp2`. In this case, the response content type is set to `application/octet-stream` and the raw response is returned as binary similar to a TCP-based Redis client. The default value for this option is `json`. Any format other than `json` and `resp2` is not allowed and will result in a HTTP 400 Bad Request. This option is not applicable to `/multi-exec` transactions endpoint, as it only returns response in JSON format. Additionally, setting the `Upstash-Encoding` header to `base64` is not permitted when the `Upstash-Response-Format` is set to `resp2` and will result in a HTTP 400 Bad Request. ```shell curl https://us1-merry-cat-32748.upstash.io/SET/foo/bar \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -H "Upstash-Reponse-Format: resp2" # +OK\r\n curl https://us1-merry-cat-32748.upstash.io/GET/foo \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -H "Upstash-Reponse-Format: resp2" # $3\r\nbar\r\n ``` ## Pipelining Upstash REST API provides support for command pipelining, allowing you to send multiple commands as a batch instead of sending them individually and waiting for responses. With the pipeline API, you can include several commands in a single HTTP request, and the response will be a JSON array. Each item in the response array corresponds to the result of a command in the same order as they were included in the pipeline. API endpoint for command pipelining is `/pipeline`. Pipelined commands should be send as a two dimensional JSON array in the request body, each row containing name of the command and its arguments. **Request syntax**: ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/pipeline \ -H "Authorization: Bearer $TOKEN" \ -d ' [ ["CMD_A", "arg0", "arg1", ..., "argN"], ["CMD_B", "arg0", "arg1", ..., "argM"], ... ] ' ``` **Response syntax**: ```json [{"result":"RESPONSE_A"},{"result":"RESPONSE_B"},{"error":"ERR ..."}, ...] ``` Execution of the pipeline is *not atomic*. Even though each command in the pipeline will be executed in order, commands sent by other clients can interleave with the pipeline. Use [transactions](#transactions) API instead if you need atomicity. For example you can write the `curl` command below to send following Redis commands using pipeline: ```redis SET key1 valuex SETEX key2 13 valuez INCR key1 ZADD myset 11 item1 22 item2 ``` ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/pipeline \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -d ' [ ["SET", "key1", "valuex"], ["SETEX", "key2", 13, "valuez"], ["INCR", "key1"], ["ZADD", "myset", 11, "item1", 22, "item2"] ] ' ``` And pipeline response will be: ```json [ { "result": "OK" }, { "result": "OK" }, { "error": "ERR value is not an int or out of range" }, { "result": 2 } ] ``` You can use pipelining when; * You need more throughput, since pipelining saves from multiple round-trip times. (*But beware that latency of each command in the pipeline will be equal to the total latency of the whole pipeline.*) * Your commands are independent of each other, response of a former command is not needed to submit a subsequent command. ## Transactions Upstash REST API supports transactions to execute multiple commands atomically. With transactions API, several commands are sent using a single HTTP request, and a single JSON array response is returned. Each item in the response array corresponds to the command in the same order within the transaction. API endpoint for transaction is `/multi-exec`. Transaction commands should be send as a two dimensional JSON array in the request body, each row containing name of the command and its arguments. **Request syntax**: ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/multi-exec \ -H "Authorization: Bearer $TOKEN" \ -d ' [ ["CMD_A", "arg0", "arg1", ..., "argN"], ["CMD_B", "arg0", "arg1", ..., "argM"], ... ] ' ``` **Response syntax**: In case when transaction is successful, multiple responses corresponding to each command is returned in json as follows: ```json [{"result":"RESPONSE_A"},{"result":"RESPONSE_B"},{"error":"ERR ..."}, ...] ``` If transaction is discarded as a whole, a single error is returned in json as follows: ```json { "error": "ERR ..." } ``` A transaction might be discarded in following cases: * There is a syntax error on the transaction request. * At least one of the commands is unsupported. * At least one of the commands exceeds the [max request size](../troubleshooting/max_request_size_exceeded). * At least one of the commands exceeds the [daily request limit](../troubleshooting/max_daily_request_limit). Note that a command may still fail even if it is a supported and valid command. In that case, all commands will be executed. Upstash Redis will not stop the processing of commands. This is to provide same semantics with Redis when there are [errors inside a transaction](https://redis.io/docs/manual/transactions/#errors-inside-a-transaction). **Example**: You can write the `curl` command below to send following Redis commands using REST transaction API: ``` MULTI SET key1 valuex SETEX key2 13 valuez INCR key1 ZADD myset 11 item1 22 item2 EXEC ``` ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/multi-exec \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -d ' [ ["SET", "key1", "valuex"], ["SETEX", "key2", 13, "valuez"], ["INCR", "key1"], ["ZADD", "myset", 11, "item1", 22, "item2"] ] ' ``` And transaction response will be: ```json [ { "result": "OK" }, { "result": "OK" }, { "error": "ERR value is not an int or out of range" }, { "result": 2 } ] ``` ## Monitor Command Upstash REST API provides Redis [`MONITOR`](https://redis.io/docs/latest/commands/monitor/) command using [Server Send Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) mechanism. API endpoint is `/monitor`. ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/monitor \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -H "Accept:text/event-stream" ``` This request will listen for Redis monitor events and incoming data will be received as: ``` data: "OK" data: 1721284005.242090 [0 0.0.0.0:0] "GET" "k" data: 1721284008.663811 [0 0.0.0.0:0] "SET" "k" "v" data: 1721284025.561585 [0 0.0.0.0:0] "DBSIZE" data: 1721284030.601034 [0 0.0.0.0:0] "KEYS" "*" ``` ## Subscribe & Publish Commands Simiar to `MONITOR` command, Upstash REST API provides Redis [`SUBSCRIBE`](https://redis.io/docs/latest/commands/subscribe/) and [`PUBLISH`](https://redis.io/docs/latest/commands/publish/) commands. The `SUBSCRIBE` endpoint works using\ [Server Send Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) mechanism. API endpoints are `/subscribe` and `/publish` Following request will subscribe to a channel named `chat`: ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/subscribe/chat \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \ -H "Accept:text/event-stream" ``` Following request will publish to a channel named `chat`: ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/publish/chat/hello \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" ``` The subscriber will receive incoming messages as: ``` data: subscribe,chat,1 data: message,chat,hello data: message,chat,how are you today? ``` ## Security and Authentication You need to add a header to your API requests as `Authorization: Bearer $TOKEN` or set the token as a url parameter `_token=$TOKEN`. ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/info \ -H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" ``` OR ```shell curl -X POST https://us1-merry-cat-32748.upstash.io/info?_token=2553feg6a2d9842h2a0gcdb5f8efe9934 ``` Upstash by default provides two separate access tokens per database: "Standard" and "Read Only". * **Standard** token has full privilege over the database, can execute any command. * **Read Only** token permits access to the read commands only. Some powerful read commands (e.g. SCAN, KEYS) are also restricted with read only token. It makes sense to use *Read Only* token when you access Upstash Redis from web and mobile clients where the token is exposed to public. You can get/copy the tokens by clicking copy button next to `UPSTASH_REDIS_REST_TOKEN` in REST API section of the console. For the *Read Only* token, just enable the "Read-Only Token" switch. Do not expose your *Standard* token publicly. *Standard* token has full privilege over the database. You can expose the *Read Only* token as it has access to read commands only. You can revoke both *Standard* and *Read Only* tokens by resetting password of your database. ### REST Token for ACL Users In addition to the tokens provided by default, you can create REST tokens for the users created via [`ACL SETUSER`](https://redis.io/commands/acl-setuser/) command. Upstash provides a custom `ACL` subcommand to generate REST tokens: `ACL RESTTOKEN`. It expects two arguments; username and user's password. And returns the REST token for the user as a string response. ``` ACL RESTTOKEN Generate a REST token for the specified username & password. Token will have the same permissions with the user. ``` You can execute `ACL RESTTOKEN` command via `redis-cli`: ```shell redis-cli> ACL RESTTOKEN default 35fedg8xyu907d84af29222ert "AYNgAS2553feg6a2d9842h2a0gcdb5f8efe9934DQ=" ``` Or via CLI on the Upstash console: If the user doesn't exist or password doesn't match then an error will be returned. ```shell redis-cli> ACL RESTTOKEN upstash fakepass (error) ERR Wrong password or user "upstash" does not exist ``` ## Redis Protocol vs REST API ### REST API Pros * If you want to access to Upstash database from an environment like CloudFlare Workers, WebAssembly, Fastly Compute\@Edge then you can not use Redis protocol as it is based on TCP. You can use REST API in those environments. * REST API is request (HTTP) based where Redis protocol is connection based. If you are running serverless functions (AWS Lambda etc), you may need to manage the Redis client's connections. REST API does not have such an issue. * Redis protocol requires Redis clients. On the other hand, REST API is accessible with any HTTP client. ### Redis Protocol Pros * If you have legacy code that relies on Redis clients, the Redis protocol allows you to utilize Upstash without requiring any modifications to your code. * By leveraging the Redis protocol, you can take advantage of the extensive Redis ecosystem. For instance, you can seamlessly integrate your Upstash database as a session cache for your Express application. ## REST API vs GraphQL API The REST API generally exhibits lower latency compared to the GraphQL API. In the case of the REST API, direct access to the database is established. However, with the GraphQL API, a proxy layer is present, responsible for accepting connections and translating GraphQL queries into the Redis protocol. If you do not have a specific GraphQL use case, we recommend REST API instead of GraphQL API. We plan to deprecate the GraphQL API in future releases. ## Cost and Pricing Upstash pricing is based on per command/request. So the same pricing listed in our [pricing](https://upstash.com/pricing/redis) applies to your REST calls too. ## Metrics and Monitoring In the current version, we do not expose any metrics specific to API calls in the console. But the metrics of the database backing the API should give a good summary about the performance of your APIs. ## REST - Redis API Compatibility | Feature | REST Support? | Notes | | ------------------------------------------------------------- | :-----------: | :---------------------------------------------------------------: | | [String](https://redis.io/commands/?group=string) | āœ… | | | [Bitmap](https://redis.io/commands/?group=bitmap) | āœ… | | | [Hash](https://redis.io/commands/?group=hash) | āœ… | | | [List](https://redis.io/commands/?group=list) | āœ… | Blocking commands (BLPOP - BRPOP - BRPOPLPUSH) are not supported. | | [Set](https://redis.io/commands/?group=set) | āœ… | | | [SortedSet](https://redis.io/commands/?group=sorted_set) | āœ… | Blocking commands (BZPOPMAX - BZPOPMIN) are not supported. | | [Geo](https://redis.io/commands/?group=geo) | āœ… | | | [HyperLogLog](https://redis.io/commands/?group=hyperloglog) | āœ… | | | [Transactions](https://redis.io/commands/?group=transactions) | āœ… | WATCH/UNWATCH/DISCARD are not supported | | [Generic](https://redis.io/commands/?group=generic) | āœ… | | | [Server](https://redis.io/commands/?group=server) | āœ… | | | [Scripting](https://redis.io/commands/?group=scripting) | āœ… | | | [Pub/Sub](https://redis.io/commands/?group=pubsub) | āš ļø | Only PUBLISH and PUBSUB are supported. | | [Connection](https://redis.io/commands/?group=connection) | āš ļø | Only PING and ECHO are supported. | | [JSON](https://redis.io/commands/?group=json) | āœ… | | | [Streams](https://redis.io/commands/?group=stream) | āœ… | Supported, except blocking versions of XREAD and XREADGROUP. | | [Cluster](https://redis.io/commands#cluster) | āŒ | | # Security Source: https://upstash.com/docs/redis/features/security Upstash has a set of features to help you secure your data. We will list them and at the end of the section we will list the best practices to improve security of database. ## TLS TLS is an optional feature which you can enable while creating your database. Once TLS is enabled, the data transfer between the client and database is encrypted. TLS is always enabled on Upstash Redis databases. ## Redis ACL With Redis ACL, you can improve security by restricting a user's access to commands and keys, so that untrusted clients have no access and trusted clients have just the minimum required access level to the database. Moreover it improves operational safety, so that clients or users accessing Redis are not allowed to damage the data or the configuration due to errors or mistakes. Check [Redis ACL documentation](https://redis.io/docs/manual/security/acl/). If you are using the REST API, you can still benefit from ACLs as explained [here](/redis/features/restapi#rest-token-for-acl-users) ## Database Credentials When you create a database, a secure password is generated. Upstash keeps the password encrypted. Use environment variables or your provider's secret management system (e.g. AWS Secrets Manager, Vercel Secrets) to keep them. Do not use them hardcoded in your code. If your password is leaked, reset the password using Upstash console. ## Encryption at Rest Encryption at REST encrypts the block storage where your data is persisted and stored. It is available with [Prod Pack](redis/overall/enterprise#prod-pack-features) add-on. ## Application Level Encryption Client side encryption can be used to encrypt data through application lifecycle. Client-side encryption is used to help protect data in use. This comes with some limitations. Operations that must operate on the data, such as increments, comparisons, and searches will not function properly. You can write client-side encryption logic directly in your own application or use functions built into clients such as the Java Lettuce cipher codec. We have plans to support encryption in our SDKs. ## IP Allowlisting We can restrict the access to your database to a set of IP addresses which will have access to your database. This is quite a strong way to secure your database, but it has some limitations. For example you can not know the IP addresses in serverless platforms such AWS Lambda and Vercel functions. ## VPC Peering VPC Peering enables you to connect to Upstash from your own VPC using private IP. Database will not be accessible from the public network. Database and your application can run in the same subnet which also minimizes data transfer costs. VPC Peering is only available for Pro databases. ## Private Link AWS Private link provides private connectivity between Upstash Database and your Redis client inside AWS infrastructure. Private link is only available for Pro databases. # Compliance Source: https://upstash.com/docs/redis/help/compliance ## Upstash Legal & Security Documents * [Upstash Terms of Service](https://upstash.com/static/trust/terms.pdf) * [Upstash Privacy Policy](https://upstash.com/static/trust/privacy.pdf) * [Upstash Data Processing Agreement](https://upstash.com/static/trust/dpa.pdf) * [Upstash Technical and Organizational Security Measures](https://upstash.com/static/trust/security-measures.pdf) * [Upstash Subcontractors](https://upstash.com/static/trust/subprocessors.pdf) ## Is Upstash SOC2 Compliant? As of July 2023, Upstash Redis is SOC2 compliant. Check our [trust page](https://trust.upstash.com/) for details. ## Is Upstash ISO-27001 Compliant? We are in process of getting this certification. Contact us ([support@upstash.com](mailto:support@upstash.com)) to learn about the expected date. ## Is Upstash GDPR Compliant? Yes. For more information, see our [Privacy Policy](https://upstash.com/static/trust/privacy.pdf). We acquire DPAs from each [subcontractor](https://upstash.com/static/trust/subprocessors.pdf) that we work with. ## Is Upstash HIPAA Compliant? Upstash is currently not HIPAA compliant. Contact us ([support@upstash.com](mailto:support@upstash.com)) if HIPAA is important for you and we can share more details. ## Is Upstash PCI Compliant? Upstash does not store personal credit card information. We use Stripe for payment processing. Stripe is a certified PCI Service Provider Level 1, which is the highest level of certification in the payments industry. ## Does Upstash conduct vulnerability scanning and penetration tests? Yes, we use third party tools and work with pen testers. We share the results with Enterprise customers. Contact us ([support@upstash.com](mailto:support@upstash.com)) for more information. ## Does Upstash take backups? Yes, we take regular snapshots of the data cluster to the AWS S3 platform. ## Does Upstash encrypt data? Customers can enable TLS while creating database/cluster, and we recommend it for production databases/clusters. Also we encrypt data at rest at request of customers. # Frequently Asked Questions Source: https://upstash.com/docs/redis/help/faq ## What is Upstash Redis? Upstash is a serverless database service compatible with RedisĀ® API. ## What is a Serverless Database? * You do not have to manage and provision servers. * You do not deal with configuring or maintaining any server. * You just use the service and pay what you use. If you are not using it, you should not be paying. ## What are the use cases? Upstash works for all the common usecases for RedisĀ®. You can use Upstash in your serverless stack. In addition, you can use Upstash as storage (or caching) for your serverless functions. See [Use Cases](/redis/overall/usecases) for more. ## Do you support all RedisĀ® API? Most of them. See [RedisĀ® API Compatibility](/redis/overall/rediscompatibility) for the list of supported commands. ## Can I use any Redis client? Yes, Upstash is compatible Redis client protocol. ## Which cloud providers do you support? Initially we have AWS and GCP. Digital Ocean is planned. ## Which regions do you support in AWS? We start with AWS-US-EAST-1 (Virginia), GCP-US-CENTRAL-1 (IOWA), AWS-US-WEST-1 (N. California), AWS-EU-WEST-1 (Ireland), AWS-APN-NE-1 (Japan). We will add new regions soon. You can expedite this by telling us your use case and the region you need by emailing to [support@upstash.com](mailto:support@upstash.com) ## Should my client be hosted in the AWS to use Upstash? No. Your client can be anywhere but the clients in AWS regions will give you better performance. ## How do you compare Upstash with ElastiCache? Upstash is serverless. With ElastiCache, you pay even you do not use the database. See [Compare](/redis/overall/compare) for more info. ## How do you compare Upstash with Redis Labs or Compose.io? Upstash is serverless. With Redis Labs or Compose.io, you always pay a lot when your data size is big but your traffic is low. In Upstash, the pricing is based on per request. See [Compare](/redis/overall/compare) for more info. ## Do you persist data? Yes, by default we write data to the disk. So in case of a failure you should not lose any data. ## Do you support Redis Cluster? We support replication in Premium type database. We do not support sharding yet. ## I have database with 10GB data, I pay nothing if I do not use it. Is that correct? You only pay for the disk storage cost that is \$0.25 per GB. For your case, you will pay \$2.5 monthly. ## What happens when I exceed the request limit on Free Database (10.000 requests per day)? The exceeding commands return exception. ## When I upgrade my free database, do I lose data? You do not lose data but clients may disconnect and reconnect. ## Upstash is much cheaper than Elasticache and Redis Labs for big data sizes (> 10GB). How is that possible? Upstash storage layer is multi tiered. We keep your data in both memory and block storage (disk). The entries that are not accessed frequently are removed from the memory but stored in disk. Latency overhead of idle entries is limited thanks to the SSD based storage. Multi tiered storage allows us to provide more flexible pricing. ## Will my data be safe? Upstash is a GDPR compliant company. We do not share any user data with third parties. See our [Legal Documents](/common/help/legal) for more information. ## How do you handle the noisy neighbour problem? Do other tenants affect my database? Databases are isolated on some aspects but still share some hardware resources such as CPU or network. To avoid noisy neighbor influence on these resources, there are specific quotas for each database. When they reach any of these quotas they are throttled using a backoff strategy. When multiple databases sharing the same hardware are close to the limits, our system can add new resources to the pool and/or migrate some of the databases to distribute the load. Also if a database exceeds its quotas very frequently, we notify users whether they want to upgrade to an upper plan. Databases in enterprise plans are placed either on dedicated or more isolated hardware due to higher resource needs. # Integration with Third Parties & Partnerships Source: https://upstash.com/docs/redis/help/integration ## Introduction In this guideline we will outline the steps to integrate Upstash into your platform (GUI or Web App) and allow your users to create and manage Upstash databases without leaving your interfaces. We will explain how to use OAuth2.0 as the underlying foundation to enable this access seamlessly. If your product or service offering utilizes Redis, Vector or QStash or if there is a common use case that your end users enable by leveraging these database resources, we invite you to be a partner with us. By integrating Upstash into your platform, you can offer a more complete package for your customers and become a one stop shop. This will also position yourself at the forefront of innovative cloud computing trends such as serverless and expand your customer base. This is the most commonly used partnership integration model that can be easily implemented by following this guideline. Recently [Cloudflare workers integration](https://blog.cloudflare.com/cloudflare-workers-database-integration-with-upstash/) is implemented through this methodology. For any further questions or partnership discussions please send us an email at [partnerships@upstash.com](mailto:partnerships@upstash.com) Before starting development to integrate Upstash into your product, please send an email to [partnerships@upstash.com](mailto:partnerships@upstash.com) for further assistance and guidance. **General Flow (High level user flow)** 1. User clicks **`Connect Upstash`**Ā button on your platform’s surface (GUI, Web App) 2. This initiates the OAuth 2.0 flow, which opens a new browser page displaying theĀ **`Upstash Login Page`**. 3. If this is an existing user, user logins with their Upstash credentials otherwise they can directly sign up for a new Upstash account. 4. Browser window redirects toĀ **`Your account has been connected`**Ā page and authentication window automatically closes. 5. After the user returns to your interface, they see their Upstash Account is now connected. ## Technical Design (SPA - Regular Web Application) 1. Users click `Connect Upstash` button from Web App. 2. Web App initiate Upstash OAuth 2.0 flow. Web App can use [Auth0 native libraries](https://auth0.com/docs/libraries). Please reach [partnerships@upstash.com](mailto:partnerships@upstash.com) to receive client id and callback url. 3. After user returns from OAuth 2.0 flow then web app will have JWT token. Web App can generate Developer Api key: ```bash curl -XPOST https://api.upstash.com/apikey \ -H "Authorization: Bearer JWT_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "APPNAME_API_KEY_TIMESTAMP" }' ``` 4. Web App need to save Developer Api Key to the backend. ## Technical Design ( GUI Apps ) 1. User clicksĀ **`Connect Upstash`**Ā button from web app. 2. Web app initiates Upstash OAuth 2.0 flow and it can useĀ **[Auth0 native libraries](https://auth0.com/docs/libraries)**. 3. App will open new browser: ``` https://auth.upstash.com/authorize?response_type=code&audience=upstash-api&scope=offline_access&client_id=XXXXXXXXXX&redirect_uri=http%3A%2F%2Flocalhost:3000 ``` Please reach [partnerships@upstash.com](mailto:partnerships@upstash.com) to receive client id. 4. After user authenticated Auth0 will redirect user to `localhost:3000/?code=XXXXXX` 5. APP can return some nice html response when Auth0 returns to `localhost:3000` 6. After getting `code` parameter from the URL query, GUI App will make http call to the Auth0 code exchange api. Example CURL request ```bash curl -XPOST 'https://auth.upstash.com/oauth/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data 'grant_type=authorization_code --data audience=upstash-api' \ --data 'client_id=XXXXXXXXXXX' \ --data 'code=XXXXXXXXXXXX' \ --data 'redirect_uri=localhost:3000' ``` Response: ```json { "access_token": "XXXXXXXXXX", "refresh_token": "XXXXXXXXXXX", "scope": "offline_access", "expires_in": 172800, "token_type": "Bearer" } ``` 7. After 6th Step the response will include `access_token`, it has 3 days TTL. GUI App will call Upstash API to get a developer api key: ```bash curl https://api.upstash.com/apikey -H "Authorization: Bearer JWT_KEY" -d '{ "name" : "APPNAME_API_KEY_TIMESTAMP" }' ``` 8. GUI App will save Developer Api key locally. Then GUI App can call any Upstash Developer API [developer.upstash.com/](https://developer.upstash.com/) ## Managing Resources After obtaining Upstash Developer Api key, your platform surface (web or GUI) can call Upstash API. For exampleĀ **[Create Database](https://developer.upstash.com/#create-database-global)**,Ā **[List Database](https://developer.upstash.com/#list-databases)** In this flow, you can ask users for region information and name of the database then can call Create Database API to complete the task Example CURL request: ```bash curl -X POST \ https://api.upstash.com/v2/redis/database \ -u 'EMAIL:API_KEY' \ -d '{"name":"myredis", "region":"global", "primary_region":"us-east-1", "read_regions":["us-west-1","us-west-2"], "tls": true}' ``` # Legal Source: https://upstash.com/docs/redis/help/legal ## Upstash Legal Documents * [Upstash Terms of Service](https://upstash.com/trust/terms.pdf) * [Upstash Privacy Policy](https://upstash.com/trust/privacy.pdf) * [Upstash Subcontractors](https://upstash.com/trust/subprocessors.pdf) # Uptime SLA Source: https://upstash.com/docs/redis/help/sla This Service Level Agreement ("SLA") applies to the use of the Upstash services, offered under the terms of our Terms of Service or other agreement with us governing your use of Upstash. This SLA does not apply to Upstash services in the Upstash Free Tier. It is clarified that this SLA is subject to the terms of the Agreement, and does not derogate therefrom (capitalized terms, unless otherwise indicated herein, have the meaning specified in the Agreement). Upstash reserves the right to change the terms of this SLA by publishing updated terms on its website, such change to be effective as of the date of publication. ### Regional and Global Database SLA Upstash will use commercially reasonable efforts to make regional and global databases available with a Monthly Uptime Percentage of at least 99.99%. In the event any of the services do not meet the SLA, you will be eligible to receive a Service Credit as described below. | Monthly Uptime Percentage | Service Credit Percentage | | --------------------------------------------------- | ------------------------- | | Less than 99.99% but equal to or greater than 99.0% | 10% | | Less than 99.0% but equal to or greater than 95.0% | 30% | | Less than 95.0% | 60% | ### SLA Credits Service Credits are calculated as a percentage of the monthly bill (excluding one-time payments such as upfront payments) for the service in the affected region that did not meet the SLA. Uptime percentages are recorded and published in the [Upstash Status Page](https://status.upstash.com). To receive a Service Credit, you should submit a claim by sending an email to [support@upstash.com](mailto:support@upstash.com). Your credit request should be received by us before the end of the second billing cycle after the incident occurred. We will apply any service credits against future payments for the applicable services. At our discretion, we may issue the Service Credit to the credit card you used. Service Credits will not entitle you to any refund or other payment. A Service Credit will be applicable and issued only if the credit amount for the applicable monthly billing cycle is greater than one dollar (\$1 USD). Service Credits may not be transferred or applied to any other account. # Support & Contact Us Source: https://upstash.com/docs/redis/help/support ## Community [Upstash Discord Channel](https://upstash.com/discord) is the best way to interact with the community. ## Team You can contact the team via [support@upstash.com](mailto:support@upstash.com) for technical support as well as questions and feedback. ## Follow Us Follow us at [X](https://x.com/upstash). ## Bugs & Issues You can help us improve Upstash by reporting issues, suggesting new features and giving general feedback in our [Community Github Repo](https://github.com/upstash/issues/issues/new). ## Enterprise Support Get [Enterprise Support](/common/help/prosupport) from the Upstash team. # Uptime Monitor Source: https://upstash.com/docs/redis/help/uptime ## Status Page You can track the uptime status of Upstash databases in [Upstash Status Page](https://status.upstash.com) ## Latency Monitor You can see the average latencies for different regions in [Upstash Latency Monitoring](https://latency.upstash.com) page # Connect Your Client Source: https://upstash.com/docs/redis/howto/connectclient Upstash works with RedisĀ® API, that means you can use any Redis client with Upstash. At the [Redis Clients](https://redis.io/clients) page you can find the list of Redis clients in different languages. Probably, the easiest way to connect to your database is to use `redis-cli`. Because it is already covered in [Getting Started](../overall/getstarted), we will skip it here. ## Database After completing the [getting started](../overall/getstarted) guide, you will see the database page as below: The information required for Redis clients is displayed here as **Endpoint**, **Port** and **Password**. Also when you click on `Clipboard` button on **Connect to your database** section, you can copy the code that is required for your client. Below, we will provide examples from popular Redis clients, but the information above should help you configure all Redis clients similarly. TLS is enabled by default for all Upstash Redis databases. It's not possible to disable it. ## upstash-redis Because upstash-redis is HTTP based, we recommend it for Serverless functions. Other TCP based clients can cause connection problems in highly concurrent use cases. **Library**: [upstash-redis](https://github.com/upstash/upstash-redis) **Example**: ```typescript import { Redis } from '@upstash/redis'; const redis = new Redis({ url: 'UPSTASH_REDIS_REST_URL', token: 'UPSTASH_REDIS_REST_TOKEN' }); (async () => { try { const data = await redis.get('key'); console.log(data); } catch (error) { console.error(error); } })(); ``` ## Node.js **Library**: [ioredis](https://github.com/luin/ioredis) **Example**: ```javascript const Redis = require("ioredis"); let client = new Redis("rediss://:YOUR_PASSWORD@YOUR_ENDPOINT:YOUR_PORT"); await client.set("foo", "bar"); let x = await client.get("foo"); console.log(x); ``` ## Python **Library**: [redis-py](https://github.com/andymccurdy/redis-py) **Example**: ```python import redis r = redis.Redis( host= 'YOUR_ENDPOINT', port= 'YOUR_PORT', password= 'YOUR_PASSWORD', ssl=True) r.set('foo','bar') print(r.get('foo')) ``` ## Java **Library**: [jedis](https://github.com/xetorthio/jedis) **Example**: ```java Jedis jedis = new Jedis("YOUR_ENDPOINT", "YOUR_PORT", true); jedis.auth("YOUR_PASSWORD"); jedis.set("foo", "bar"); String value = jedis.get("foo"); System.out.println(value); ``` ## Go **Library**: [redigo](https://github.com/gomodule/redigo) **Example**: ```go func main() { c, err := redis.Dial("tcp", "YOUR_ENDPOINT:YOUR_PORT", redis.DialUseTLS(true)) if err != nil { panic(err) } _, err = c.Do("AUTH", "YOUR_PASSWORD") if err != nil { panic(err) } _, err = c.Do("SET", "foo", "bar") if err != nil { panic(err) } value, err := redis.String(c.Do("GET", "foo")) if err != nil { panic(err) } println(value) } ``` # Connect with upstash-redis Source: https://upstash.com/docs/redis/howto/connectwithupstashredis [upstash-redis](https://github.com/upstash/redis-js) is an HTTP/REST based Redis client built on top of [Upstash REST API](/redis/features/restapi). For more information, refer to the documentation of Upstash redis client ([TypeScript](/redis/sdks/ts/overview) & [Python](/redis/sdks/py/overview)). It is the only connectionless (HTTP based) Redis client and designed for: * Serverless functions (AWS Lambda ...) * Cloudflare Workers (see [the example](https://github.com/upstash/upstash-redis/tree/master/examples/workers-with-upstash)) * Fastly Compute\@Edge * Next.js, Jamstack ... * Client side web/mobile applications * WebAssembly * and other environments where HTTP is preferred over TCP. See [the list of APIs](https://docs.upstash.com/features/restapi#rest---redis-api-compatibility) supported. ## Quick Start ### Install ```bash npm install @upstash/redis ``` ### Usage ```typescript import { Redis } from "@upstash/redis"; const redis = new Redis({ url: "UPSTASH_REDIS_REST_URL", token: "UPSTASH_REDIS_REST_TOKEN", }); (async () => { try { const data = await redis.get("key"); console.log(data); } catch (error) { console.error(error); } })(); ``` If you define `UPSTASH_REDIS_REST_URL` and`UPSTASH_REDIS_REST_TOKEN` environment variables, you can load them automatically. ```typescript import { Redis } from "@upstash/redis"; const redis = Redis.fromEnv()(async () => { try { const data = await redis.get("key"); console.log(data); } catch (error) { console.error(error); } })(); ``` # Datadog - Upstash Redis Integration Source: https://upstash.com/docs/redis/howto/datadog This guide will walk you through the steps to seamlessly connect your Datadog account with Upstash for enhanced monitoring and analytics. **Integration Scope** Upstash Datadog Integration only covers Pro databases or those included in the Enterprise Plan. ## **Step 1: Log in to Your Datadog Account** 1. Open your web browser and navigate to [Datadog](https://www.datadoghq.com/). 2. Log in to your Datadog account. ## **Step 2: Install Upstash Application** 1. Once logged in, navigate to the "Integrations" page in Datadog. 2. Search for "Upstash" in the integrations list and click on it. ![integration-tab.png](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/datadog/integration-tab.png) Let’s click on the "Install" button to add Upstash to your Datadog account. ![installation.png](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/datadog/installation.png) ## **Step 3: Connect Accounts** After installing Upstash, click on the "Connect Accounts" button and Datadog will redirect you to the Upstash site for account integration. ![connect-acc.png](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/datadog/connect-acc.png) ## **Step 4: Select Account to Integrate** 1. On the Upstash site, you will be prompted to select the Datadog account you want to integrate. 2. Choose the appropriate Datadog account from the list. Upstash Datadog Integration allows you to integrate personal and team based accounts. **Caveats;** * This integration can only be executed only one time.If you would like to extend list of the team in integration please re-establish the integration from scratch. ![personal.png](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/datadog/personal.png) ![team.png](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/datadog/team.png) ## **Step 5: Wait for Metrics Availability** Once you've selected your Datadog account, Upstash will begin the integration process and please be patient while the metrics are being retrieved. This may take a few moments. And here we go, metrics will be available in Upstash Overview Dashboard ! ![upstash-dashboard.png](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/datadog/upstash-dashboard.png) ## **Step 6: Datadog Integration Removal Process** Navigate to Integration Tab on your Datadog account, Once logged in, navigate to the "Integration" tab and continue with Datadog part. If you would like to remove your integration between Upstash and Datadog account press "Remove". ### Confirm Removal: Upstash will suspend all metric publishing process after the you remove Datadog Integration. After removing the integration on the Upstash side, it's crucial to go to your Datadog account and remove any related API keys or configurations associated with the integration. ## Pricing If you choose to integrate Datadog via Upstash, there will be an additional cost of \$5 per month. This charge will be reflected in your monthly invoice accordingly. ## **Conclusion** Congratulations! You have successfully integrated your Datadog account with Upstash. You will now have access to enhanced monitoring and analytics for your Datadog metrics. Feel free to explore Upstash's features and dashboards to gain deeper insights into your system's performance. If you encounter any issues or have questions, please refer to the Upstash support documentation or contact our support team for assistance. # EMQX - Upstash Redis Integration Source: https://upstash.com/docs/redis/howto/emqxintegration EMQX, a robust open-source MQTT message broker, is engineered for scalable, distributed environments, prioritizing high availability, throughput, and minimal latency. As a preferred protocol in the IoT landscape, MQTT (Message Queuing Telemetry Transport) excels in enabling devices to effectively publish and subscribe to messages. Offered by EMQ, EMQX Cloud is a comprehensively managed MQTT service in the cloud, inherently scalable and secure. Its design is particularly advantageous for IoT applications, providing dependable MQTT messaging services. This tutorial guides you on streaming MQTT data to Upstash via data integration. It allows clients to send temperature and humidity data to EMQX Cloud using MQTT and channel it into Upstash for Redis storage. ## Setting Up Redis Database with Upstash 1. Log in and create a Redis Database by clicking the **Create Database** button on [Upstash Console](https://console.upstash.com). 2. Name your database and select a region close to your EMQX Cloud for optimal performance. 3. Click **Create** to have your serverless Redis Database ready. ![upstash](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/upstash_redis_01.png) ### Database Details Access the database console for the necessary information for further steps. ![upstash](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/upstash_redis_02.png) The above steps, conclude the initial setup for Upstash. ## Establishing Data Integration with Upstash ### Activating EMQX Cloud's NAT Gateway 1. Log into the EMQX Cloud console and go to the deployment Overview. 2. Select **NAT Gateway** at the bottom and click **Subscribe Now**. ![NAT](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/public_nat.png) ### Configuring Data Integration 1. In the EMQX Cloud console, choose **Data Integrations** and select **Upstash for Redis**. ![create resource](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/upstash_redis_03.png) 2. Input **Endpoints** info from the Redis detail page into the **Redis Server** field, including the port. Enter the password in **Password** and click **Test** to ensure connectivity. ![create resource](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/upstash_redis_04.png) 3. Click **New** to add a Redis resource. A new Upstash for Redis will appear under **Configured Resources**. 4. Formulate a new SQL rule in the **SQL** field. This rule will read from `temp_hum/emqx` and append client\_id, topic, timestamp. * `up_timestamp`: Message report time * `client_id`: Publishing client's ID * `temp`: Temperature data * `Hum`: Humidity data ```sql SELECT timestamp as up_timestamp, clientid as client_id, payload.temp as temp, payload.hum as hum FROM "temp_hum/emqx" ``` ![rule sql](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/kafka_create_sql.png) 5. Execute an SQL test with payload, topic, client info. Successful results confirm the rule's effectiveness. ![rule sql](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/kafka_create_sql_test.png) 6. Proceed to **Next** to link an action. The rule will store the timestamp, client ID, temperature, and humidity in Redis. Click **Confirm**. ```bash HMSET ${client_id} ${up_timestamp} ${temp} ``` ![rule sql](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/upstash_redis_05.png) 7. Post-binding, click **View Details** for the rule SQL and bound actions. 8. To review rules, select **View Created Rules** in Data Integrations. Check detailed metrics in the **Monitor** column. ## Testing the Data Bridge 1. Simulate temperature and humidity data with [MQTTX](https://mqttx.app/). Add connection address and client authentication for the EMQX Dashboard. ![MQTTX](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/upstash_kafka_06.png) 2. In Upstash Console, under Data Browser, select a client entry to review messages. ![monitor](https://raw.githubusercontent.com/emqx/cloud-docs/master/en_US/rule_engine/_assets/upstash_redis_07.png) # Get Started with AWS Lambda Source: https://upstash.com/docs/redis/howto/getstartedawslambda You can connect to Upstash database from your Lambda functions using your favorite Redis client. You do not need any extra configuration. The only thing to note is you should use the same region for your Lambda function and database to minimize latency. If you do not have any experience with AWS Lambda functions, you can follow the following tutorial. The tutorial explains the required steps to implement an AWS Lambda function that takes the key/value as parameters from APIGateway then inserts an entry (key/value) to the database which is on Upstash. We have implemented the function in Node.js, but the steps and the logic are quite similar in other languages. This example uses Redis clients. If you expect many concurrent AWS Lambda invocation then we recommend using **[upstash-redis](/redis/howto/connectwithupstashredis)** which is HTTP/REST based. **Step 1: Create database on Upstash** If you do not have one, create a database following this [guide](../overall/getstarted). **Step 2: Create a Node project** Create an empty folder for your project and inside the folder create a node project with the command: ``` npm init ``` Then install the redis client with: ``` npm install ioredis ``` Now create index.js file. Replace the Redis URL in the below code. ```javascript var Redis = require("ioredis"); if (typeof client === "undefined") { var client = new Redis("rediss://:YOUR_PASSWORD@YOUR_ENDPOINT:YOUR_PORT"); } exports.handler = async (event) => { await client.set("foo", "bar"); let result = await client.get("foo"); let response = { statusCode: 200, body: JSON.stringify({ result: result, }), }; return response; }; ``` **Step 3: Deploy Your Function** Our function is ready to deploy. Normally you could copy-paste your function code to AWS Lambda editor. But here it is not possible because we have an extra dependency (redis-client). So we will zip and upload our function. When you are in your project folder, create a zip with this command: ``` zip -r app.zip . ``` Now open your AWS console, from the top-right menu, select the region that you created your database in Upstash. Then find or search the lambda service, click on `Create Function` button. Enter a name for your function and select `Node.js 14.x` as runtime. Click `Create Function`. Now you are on the function screen, scroll below to `Function Code` section. On `Code entry type` selection, select `Upload a .zip file`. Upload the `app.zip` file you have just created and click on the `Save` button on the top-right. You need to see your code as below: Now you can test your code. Click on the `Test` button on the top right. Create an event like the below: ``` { "key": "foo", "value": "bar" } ``` Now, click on Test. You will see something like this: Congratulations, now your lambda function inserts entry to your Upstash database. **What can be the next?** * You can write and deploy another function to just get values from the database. * You can learn better ways to deploy your functions such as [serverless framework](https://serverless.com/) and [AWS SAM](https://aws.amazon.com/serverless/sam/) * You can integrate [API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html) so you can call your function via http. * You can learn about how to monitor your functions from CloudWatch as described [here](https://docs.aws.amazon.com/lambda/latest/dg//monitoring-functions-logs.html) . #### Redis Connections in AWS Lambda Although Redis connections are very lightweight, a new connection inside each Lambda function can cause a notable latency. On the other hand, reusing Redis connections inside the AWS Lambda functions has its own drawbacks. When AWS scales out Lambda functions, the number of open connections can rapidly increase. Fortunately, Upstash detects and terminates the idle and zombie connections thanks to its smart connection handling algorithm. Since this algorithm is used; we have been recommending caching your Redis connection in serverless functions. See [the blog post](https://blog.upstash.com/serverless-database-connections) about the database connections in serverless functions. Below is our findings about various Redis clients' behaviours when connection is created, a single command is submitted and then connection is closed. **Note that these commands (AUTH, INFO, PING, QUIT, COMMAND) are not billed.** | Client | #Commands | Issued Commands | | ----------------------------------------------------- | :-------: | :----------------: | | [redis-cli](https://redis.io/topics/rediscli) | 2 | AUTH - COMMAND | | [node-redis](https://github.com/NodeRedis/node-redis) | 3 | AUTH - INFO - QUIT | | [ioredis](https://github.com/luin/ioredis) | 3 | AUTH - INFO - QUIT | | [redis-py](https://github.com/andymccurdy/redis-py) | 1 | AUTH | | [jedis](https://github.com/xetorthio/jedis) | 2 | AUTH - QUIT | | [lettuce](https://github.com/lettuce-io/lettuce-core) | 2 | AUTH - QUIT | | [go-redis](https://github.com/go-redis/redis) | 1 | AUTH | # Get Started with Cloudflare Workers Source: https://upstash.com/docs/redis/howto/getstartedcloudflareworkers This tutorial showcases using Redis with REST API in Cloudflare Workers. We will write a sample edge function (Cloudflare Workers) which will show a custom greeting depending on the location of the client. We will load the greeting message from Redis so you can update it without touching the code. See [the code](https://github.com/upstash/examples/tree/master/examples/using-cloudflare-workers). ### Why Upstash? * Cloudflare Workers does not allow TCP connections. Upstash provides REST API on top of the Redis database. * Upstash is a serverless offering with per-request pricing which fits for edge and serverless functions. * Upstash Global database provides low latency all over the world. ### Step-1: Create Redis Database Create a free Global database from [Upstash Console](https://console.upstash.com). Find your REST URL and token in the database details page in the console. Copy them. Connect your database with redis-cli and add some greetings ```shell usw1-selected-termite-30690.upstash.io:30690> set GB "Ey up?" OK usw1-selected-termite-30690.upstash.io:30690> set US "Yo, what’s up?" OK usw1-selected-termite-30690.upstash.io:30690> set TR "Naber dostum?" OK usw1-selected-termite-30690.upstash.io:30690> set DE "Was ist los?" ``` ### Step-2: Edge Function The best way to work with Cloudflare Workers is to use [Wrangler](https://developers.cloudflare.com/workers/get-started/guide). After installing and configuring wrangler, create a folder for your project inside the folder run: `wrangler init` Choose `yes` to create package.json, `no` to typescript and `yes` to create a worker in src/index.js. It will create `wrangler.toml`, `package.json` and `src/index.js`. Append the Upstash REST URL and token to the toml as below: ```toml # wrangler.toml # existing config [vars] UPSTASH_REDIS_REST_TOKEN = "AX_sASQgODM5ZjExZGEtMmI3Mi00Mjcwk3NDIxMmEwNmNkYjVmOGVmZTk5MzQ=" UPSTASH_REDIS_REST_URL = "https://us1-merry-macaque-31458.upstash.io/" ``` Install upstash-redis: `npm install @upstash/redis` Replace `src/index.js` with the following: ```javascript // src/index.js import { Redis } from "@upstash/redis/cloudflare"; export default { async fetch(request, env) { const redis = Redis.fromEnv(env); const country = request.headers.get("cf-ipcountry"); if (country) { const greeting = await redis.get(country); if (greeting) { return new Response(greeting); } } return new Response("Hello!"); }, }; ``` The code tries to find out the user's location checking the "cf-ipcountry" header. Then it loads the correct greeting for that location using the Redis REST API. ## Run locally Run `wrangler dev` and open your browser at [localhost:8787](http://localhost:8787). ## Build and Deploy Build and deploy your app to Cloudflare by running: `wrangler publish` The url of your app will be logged: [https://using-cloudflare-workers.upstash.workers.dev/](https://using-cloudflare-workers.upstash.workers.dev/) ## Typescript example We also have a typescript example, available [here](https://github.com/upstash/upstash-redis/tree/main/examples/cloudflare-workers-with-typescript). # Get Started with Google Cloud Functions Source: https://upstash.com/docs/redis/howto/getstartedgooglecloudfunctions ### Prerequisites: * A GCP account for Google Cloud functions. * Install [Google Cloud SDK](https://cloud.google.com/sdk/docs/install). * An Upstash account for Serverless Redis. ### Step 1: Init the Project * Create a folder, then run `npm init` inside the folder. ### Step 2: Install a Redis Client Our only dependency is redis client. Install go-redis via `npm install ioredis` ### Step 3: Create a Redis Database Create a Redis database from Upstash console. **Select the GCP US-Central-1 as the region.** Free tier should be enough. It is pretty straight forward but if you need help, check [getting started](../overall/getstarted) guide. In the database details page, click the Connect button. You will need the endpoint and password in the next step. ### Step 4: The function Code Create index.js as below: ```javascript var Redis = require("ioredis"); if (typeof client === "undefined") { var client = new Redis("rediss://:YOUR_PASSWORD@YOUR_ENDPOINT:YOUR_PORT"); } exports.helloGET = async (req, res) => { let count = await client.incr("counter"); res.send("Page view:" + count); }; ``` The code simply increments a counter in Redis database and returns its value in json format. ### Step 5: Deployment Now we are ready to deploy our API. Deploy via: ```shell gcloud functions deploy helloGET \ --runtime nodejs14 --trigger-http --allow-unauthenticated ``` You will see the URL of your Cloud Function. Click to the URL to check if it is working properly. ```shell httpsTrigger: securityLevel: SECURE_OPTIONAL url: https://us-central1-functions-317005.cloudfunctions.net/helloGET ``` In case of an issue, you can check the logs of your Cloud Function in the GCP console as below. # Import/Export Data Source: https://upstash.com/docs/redis/howto/importexport ## Using Upstash Console You can use the migration wizard in the [Upstash console](https://console.upstash.com) to import your Redis to Upstash. In the database list page, click on the `Import` button, you will see the dialog like below: You can move your data from either an Upstash database or a database in another provider (or on premise). All the data will be deleted (flushed) in the destination database before the migration process starts. ## Using upstash-redis-dump You can also use the [upstash-redis-dump](https://github.com/upstash/upstash-redis-dump) tool import/export data from another Redis. The below is an example how to dump and import data: ```shell $ upstash-redis-dump -db 0 -host eu1-moving-loon-6379.upstash.io -port 6379 -pass PASSWORD -tls > redis.dump Database 0: 9 keys dumped ``` See [upstash-redis-dump repo](https://github.com/upstash/upstash-redis-dump) for more information. # ioredis note Source: https://upstash.com/docs/redis/howto/ioredisnote This example uses ioredis, you can copy the connection string from the `Node` tab in the console. # Use IP Allowlist Source: https://upstash.com/docs/redis/howto/ipallowlist IP Allowlist is available on all plans except for the free plan. IP Allowlist can be used to restrict which IP addresses are permitted to access your database by comparing a connection's address with predefined CIDR blocks. This feature enhances database security by allowing connections only from specified IP addresses. For example if you have dedicated production servers with static IP addresses, enabling IP allowlist blocks connections from other addresses. ![allowlist](https://mintlify.s3.us-west-1.amazonaws.com/upstash/img/ipallowlist/ipallowlist.png) ## Enabling IP Allowlist By default, any IP address can be used to connect to your database. You must add at least one IP range to enable the allowlist. You can manage added IP ranges in the `Configuration` section on the database details page. You can either provide * IPv4 address, e.g. `37.237.15.43` * CIDR block, e.g. `181.49.172.0/24` Currently, IP Allowlist only supports IPv4 addresses. You can use more than one range to allow multiple clients. Meeting the criteria of just one is enough to establish a connection. It may take a few minutes for changes to propagate. # Listen Keyspace Notifications Source: https://upstash.com/docs/redis/howto/keyspacenotifications Upstash allows you to listen for keyspace notifications over pubsub channels to receive events for changes over the keys. For each event that occurs, two kinds of events are fired over the corresponding pubsub channels: * A keyspace event that will use the pubsub channel for the key, possibly containing other events for the same key * A keyevent event that will use the pubsub channel for the event, possibly containing other events for the different keys The channel names and their content are of the form: * `__keyspace@0__:keyname` channel with the values of the event names for the keyspace notifications * `__keyevent@0__:eventname` channel with the values of the key names for the keyevent notifications ## Enabling Notifications By default, all keyspace and keyevent notifications are off. To enable it, you can use the `CONFIG SET` command, and set the `notify-keyspace-events` options to one of the appropriate flags described below. Each keyspace and keyevent notification fired might have an effect on the latency of the commands as the events are delivered to the listening clients and cluster members for multi-replica deployments. Therefore, it is advised to only enable the minimal subset of the notifications that are needed. | Flag | Description | | ---- | --------------------------- | | K | Keyspace events | | E | Keyevent events | | g | Generic command events | | \$ | String command events | | l | List command events | | s | Set command events | | h | Hash command events | | z | Sorted set command events | | t | Stream command events | | d | Module(JSON) command events | | x | Expiration events | | e | Eviction events | | m | Key miss events | | n | New key events | | A | Alias for g\$lshztxed | At least one of the `K` or `E` flags must be present in the option value. For example, you can use the following command to receive keyspace notifications only for the hash commands: ```bash curl -X POST \ -d '["CONFIG", "SET", "notify-keyspace-events", "Kh"]' \ -H "Authorization: Bearer $UPSTASH_REDIS_REST_TOKEN" \ $UPSTASH_REDIS_REST_URL ``` ```bash redis-cli --tls -u $UPSTASH_REDIS_CLI_URL config set notify-keyspace-events Kh ``` You can listen for all the channels using redis-cli to test the effect of the above command: ```bash redis-cli --tls -u $UPSTASH_REDIS_CLI_URL --csv psubscribe '__key*__:*' ``` ### Disabling Notifications You can reuse the `CONFIG SET` command and set `notify-keyspace-events` option to empty string to disable all keyspace and keyevent notifications. ```bash curl -X POST \ -d '["CONFIG", "SET", "notify-keyspace-events", ""]' \ -H "Authorization: Bearer $UPSTASH_REDIS_REST_TOKEN" \ $UPSTASH_REDIS_REST_URL ``` ```bash redis-cli --tls -u $UPSTASH_REDIS_CLI_URL config set notify-keyspace-events "" ``` ### Checking Notification Configuration `CONFIG GET` command can be used the get the current value of the `notify-keyspace-events` option to see the active keyspace and keyevent notifications configuration. ```bash curl -X POST \ -d '["CONFIG", "GET", "notify-keyspace-events"]' \ -H "Authorization: Bearer $UPSTASH_REDIS_REST_TOKEN" \ $UPSTASH_REDIS_REST_URL ``` ```bash redis-cli --tls -u $UPSTASH_REDIS_CLI_URL config get notify-keyspace-events ``` # Metrics and Charts Source: https://upstash.com/docs/redis/howto/metricsandcharts There are many metrics and charts in Upstash console. In this document, we will explain what each of these charts refers to. There are two pages where you can see charts and metrics: ## Database List The charts on this page give aggregated and total information about the database and your usage. In this chart, all your databases are listed. You can click on the name of the database that you want to see detailed information. Also, the following information is listed for each database: * The region of the database * The current size of the data * The current count of active connections: Not that if your connections are short-lived then you may see 0 here most of the time. ## Database Detail The charts on this page show metrics that are specific to the selected database. ### Current Month * This chart shows the daily cost of the database. The chart covers the last 5 days. ### Daily Request This chart shows the daily total number of requests to the database. The chart covers the last 5 days. ### Throughput Throughput chart shows throughput values for reads, writes and commands (all commands including reads and writes) per second. The chart covers the last 1 hour and it is updated every 10 seconds. ### Service Time Latency This chart shows the processing time of the request between it is received by the server and the response is sent to the caller. It shows the times in max, mean, min, 99.9 percentile and 99.99 percentile. The chart covers the last 1 hour and it is updated every 10 seconds. ### Data Size This chart shows the data size of your database. The chart covers the last 24 hours and it is updated every 10 seconds. ### Connections This chart shows the number of active client connections. It shows the number of open connections plus the number of short-lived connections that started and terminated in 10 seconds period. The chart covers the last 1 hour and it is updated every 10 seconds. ### Key Space This chart shows the number of keys. The chart covers the last 24 hours and it is updated every 10 seconds. ### Hits / Misses This chart shows the number of hits per second and misses per second. The chart covers the last 1 hour and it is updated every 10 seconds. # Migrate Regional to Global Database Source: https://upstash.com/docs/redis/howto/migratefromregionaltoglobal This guide will help you migrate your data from a regional Upstash Redis database to a global database. If your database is Upstash Regional, we strongly recommend you to migrate to [Upstash Redis Global](https://upstash.com/docs/common/concepts/global-replication). Our Regional Redis databases are legacy and deprecated. ## Why Migrate? * New infrastructure, more modern and more secure * Upstash Global is SOC-2 and HIPAA compatible * Enhanced feature set: New features are only made available on Upstash Global * Ability to add/remove read regions on the go * Better performance as per our benchmarks ## Prerequisites Before starting the migration, make sure you have: 1. An existing regional Upstash Redis database (source) 2. A new global Upstash Redis database (destination) 3. Access to both databases' credentials (connection strings, passwords) ## Migration Process There are several official ways to migrate your data: If you are using RBAC, please note that they are not migrated automatically. You need to redefine ACL users for new the global database after migration. ### 1. Using Backup/Restore (Recommended for AWS Regional Databases) If your regional database is hosted in AWS, you can use Upstash's backup/restore feature: 1. Create a backup of your regional database: * Go to your regional database details page * Navigate to the `Backups` tab * Click the `Backup` button * Provide a unique name for your backup * Wait for the backup process to complete During backup creation, some database operations will be temporarily unavailable. 2. Restore the backup to your global database: * Go to your global database details page * Navigate to the `Backups` tab * Click `Restore...` * Select your regional database as the source * Select the backup you created * Click `Start Restore` The restore operation will flush (delete) all existing data in your (destination) global database before restoring the backup. ### 2. Using Upstash Console Migration Wizard The easiest way to migrate your data is using the Upstash Console's built-in migration wizard: 1. Go to [Upstash Console](https://console.upstash.com) 2. In the database list page, click the `Import` button 3. Select your source (regional) database 4. Select your destination (global) database 5. Follow the wizard instructions to complete the migration Note: The destination database will be flushed before migration starts. ### 3. Using upstash-redis-dump Another reliable method is using the official [upstash-redis-dump](https://github.com/upstash/upstash-redis-dump) tool: 1. Install upstash-redis-dump: ```bash npm install -g upstash-redis-dump ``` 2. Export data from regional database: ```bash upstash-redis-dump -db 0 -host YOUR_REGIONAL_HOST -port YOUR_DATABASE_PORT -pass YOUR_PASSWORD -tls > redis.dump ``` 3. Import data to global database: ```bash cat redis.dump | upstash-redis-dump -db 0 -host YOUR_GLOBAL_HOST -port 6379 -pass YOUR_PASSWORD -tls -import ``` ## Verification After migration, verify your data: 1. Compare key counts in both databases 2. Sample test some keys to ensure data integrity ## Post-Migration Steps 1. Update your application configuration to use the new Global database URL 2. Test your application thoroughly with the new database 3. Monitor performance and consistency across regions 4. Keep the regional database as backup for a few days 5. Once verified, you can safely delete the regional database ## Need Help? If you encounter any issues during migration, please contact Upstash support via chat, [support@upstash.com](mailto:support@upstash.com) or visit our Discord community for assistance. # Monitor your usage Source: https://upstash.com/docs/redis/howto/monitoryourusage We support the Redis `MONITOR` command, a debugging command that allows you to see all requests processed by your Redis instance in real-time. ## Monitoring Your Usage - Video Guide In this video, we'll walk through setting up a monitor instance step-by-step.