{"id":22089828,"url":"https://github.com/speakeasy-api/speakeasy-typescript-sdk","last_synced_at":"2026-03-10T05:31:50.059Z","repository":{"id":56742584,"uuid":"517923485","full_name":"speakeasy-api/speakeasy-typescript-sdk","owner":"speakeasy-api","description":"Speakeasy SDK for TypeScript APIs","archived":false,"fork":false,"pushed_at":"2023-02-10T23:57:07.000Z","size":267,"stargazers_count":2,"open_issues_count":0,"forks_count":3,"subscribers_count":14,"default_branch":"main","last_synced_at":"2026-01-24T01:46:08.470Z","etag":null,"topics":["embeds","har","middleware","request-logging","requests","sdk","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/speakeasy-api.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-07-26T05:20:17.000Z","updated_at":"2025-05-28T07:14:17.000Z","dependencies_parsed_at":"2025-09-01T10:04:26.091Z","dependency_job_id":"0032ea61-cb3f-4216-b269-5facb285a3b5","html_url":"https://github.com/speakeasy-api/speakeasy-typescript-sdk","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/speakeasy-api/speakeasy-typescript-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fspeakeasy-typescript-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fspeakeasy-typescript-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fspeakeasy-typescript-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fspeakeasy-typescript-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/speakeasy-api","download_url":"https://codeload.github.com/speakeasy-api/speakeasy-typescript-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fspeakeasy-typescript-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30326071,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T05:25:20.737Z","status":"ssl_error","status_checked_at":"2026-03-10T05:25:17.430Z","response_time":106,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embeds","har","middleware","request-logging","requests","sdk","typescript"],"created_at":"2024-12-01T02:14:24.210Z","updated_at":"2026-03-10T05:31:50.027Z","avatar_url":"https://github.com/speakeasy-api.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# speakeasy-typescript-sdk\n\n![180100416-b66263e6-1607-4465-b45d-0e298a67c397](https://user-images.githubusercontent.com/68016351/181640742-31ab234a-3b39-432e-b899-21037596b360.png)\n\nSpeakeasy is your API Platform team as a service. Use our drop in SDK to manage all your API Operations including\ncustomer facing embeds for request logs, usage metrics, understanding API drift and more.\n\nThe Speakeasy Typescript SDK for evaluating API requests/responses.\n\n## Requirements\n\nSupported frameworks:\n\n* Express\n* NestJs\n\n## Usage\n\nThe Speakeasy Typescript SDK is hosted on NPM and can be installed with the following command:\n\n```bash\nnpm install @speakeasy-api/speakeasy-typescript-sdk\n```\n\n### Minimum configuration\n\n[Sign up for free on our platform](https://www.speakeasyapi.dev/). After you've created a workspace and generated an API\nkey enable Speakeasy in your API as follows:\n\n#### Express\n\nConfigure Speakeasy in your middleware chain as follows:\n\n```typescript\nimport speakeasy, {Config} from \"@speakeasy-api/speakeasy-typescript-sdk\";\nimport express from \"express\";\n\nconst app = express();\n\n// Configure the global speakeasy SDK instance\nconst cfg: Config = {\n    apiKey: \"YOUR API KEY HERE\",       // retrieve from Speakeasy API dashboard.\n    apiID: \"YOUR API ID HERE\",         // enter a name that you'd like to associate captured requests with.\n    // This name will show up in the Speakeasy dashboard. e.g. \"PetStore\" might be a good ApiID for a Pet Store's API.\n    // No spaces allowed.\n    versionID: \"YOUR VERSION ID HERE\", // enter a version that you would like to associate captured requests with.\n    // The combination of ApiID (name) and VersionID will uniquely identify your requests in the Speakeasy Dashboard.\n    // e.g. \"v1.0.0\". You can have multiple versions for the same ApiID (if running multiple versions of your API)\n    port: 3000,                        // The port number your express app is listening on (required to build full URLs on non-standard ports)\n};\nspeakeasy.configure(cfg);\n\n// Add the speakeasy middleware to your express app\napp.use(speakeasy.expressMiddleware());\n\n// Rest of your express app setup code\n```\n\n#### NestJS\n\nConfigure Speakeasy in your NestJS app as follows:\n\n```typescript\nimport speakeasy, {Config} from '@speakeasy-api/speakeasy-typescript-sdk';\nimport {MiddlewareConsumer, Module, NestModule} from '@nestjs/common';\n\nimport {AppController} from './app.controller';\nimport {AppService} from './app.service';\n\n@Module({\n    imports: [],\n    controllers: [AppController],\n    providers: [AppService],\n})\nexport class AppModule implements NestModule {\n    configure(consumer: MiddlewareConsumer) {\n        // Configure the global speakeasy SDK instance\n        const cfg: Config = {\n            apiKey: \"YOUR API KEY HERE\",\t\t// retrieve from Speakeasy API dashboard.\n            apiID: \"YOUR API ID HERE\", \t\t// enter a name that you'd like to associate captured requests with.\n            // This name will show up in the Speakeasy dashboard. e.g. \"PetStore\" might be a good ApiID for a Pet Store's API.\n            // No spaces allowed.\n            versionID: \"YOUR VERSION ID HERE\",\t// enter a version that you would like to associate captured requests with.\n            // The combination of ApiID (name) and VersionID will uniquely identify your requests in the Speakeasy Dashboard.\n            // e.g. \"v1.0.0\". You can have multiple versions for the same ApiID (if running multiple versions of your API)\n            port: 3000,\t\t\t\t// The port number your express app is listening on (required to build full URLs on non-standard ports)\n        };\n        speakeasy.configure(cfg);\n\n        // Configure the NestJS middleware for the routes of you Controller\n        consumer.apply(speakeasy.nestJSMiddleware()).forRoutes(AppController);\n    }\n}\n```\n\nBuild and deploy your app and that's it. Your API is being tracked in the Speakeasy workspace you just created\nand will be visible on the dashboard next time you log in. Visit our [docs site](https://docs.speakeasyapi.dev/) to\nlearn more.\n\n### Advanced configuration\n\nThe Speakeasy SDK provides both a global and per Api configuration option. If you want to use the SDK to track multiple\nApis or Versions from the same service you can configure individual instances of the SDK.\n\n#### Express\n\n```typescript\nimport {Config, SpeakeasySDK} from \"@speakeasy-api/speakeasy-typescript-sdk\";\nimport express from \"express\";\n\nconst app = express();\n\n// Configure a new instance of the SDK for the store API\nconst storeSDK = new SpeakeasySDK({\n    apiKey: \"YOUR API KEY HERE\",      // retrieved from Speakeasy API dashboard.\n    apiID: \"store_api\",               // this is an ID you provide that you would like to associate captured requests with.\n    versionID: \"1.0.0\",               // this is a Version you provide that you would like to associate captured requests with.\n    port: 3000,                       // The port number your express app is listening on (required to build full URLs on non-standard ports)\n});\n\n// Configure a new instance of the SDK for the product AP\nconst productSDK = new SpeakeasySDK({\n    apiKey: \"YOUR API KEY HERE\",      // retrieved from Speakeasy API dashboard.\n    apiID: \"product_api\",             // this is an ID you provide that you would like to associate captured requests with.\n    versionID: \"1.0.0\",               // this is a Version you provide that you would like to associate captured requests with.\n    port: 3000,                       // The port number your express app is listening on (required to build full URLs on non-standard ports)\n});\n\n// The different instances of the SDK (with differnt IDs or even versions assigned) can be used to associate requests with different APIs and Versions.\nconst storeRouter = app.route(\"/store\");\nstoreRouter.use(storeSDK.expressMiddleware());\n\nconst productsRouter = app.route(\"/products\");\nproductsRouter.use(productSDK.expressMiddleware());\n\n// Rest of your express app setup code\n```\n\n##### NestJS\n\n```typescript\nimport {Config, SpeakeasySDK} from '@speakeasy-api/speakeasy-typescript-sdk';\nimport {MiddlewareConsumer, Module, NestModule} from '@nestjs/common';\n\nimport {AppController} from './app.controller';\nimport {AppService} from './app.service';\n\n@Module({\n    imports: [],\n    controllers: [AppController],\n    providers: [AppService],\n})\nexport class AppModule implements NestModule {\n    configure(consumer: MiddlewareConsumer) {\n        // Configure a speakeasy SDK instance\n        const cfg: Config = {\n            apiKey: \"YOUR API KEY HERE\",\t\t\t// retrieve from Speakeasy API dashboard.\n            apiID: \"YOUR API ID HERE\", \t\t\t// custom Api ID to associate captured requests with.\n            versionID: \"YOUR VERSION ID HERE\",\t// custom Version ID to associate captured requests \n            port: 3000,\t\t\t\t\t\t\t// The port number your express app is listening on (required to build full URLs on non-standard ports)\n        };\n        const sdk = new SpeakeasySDK(cfg);\n\n        // Configure the NestJS middleware for the routes of you Controller\n        consumer.apply(sdk.nestJSMiddleware()).forRoutes(AppController);\n    }\n}\n```\n\nThis allows multiple instances of the SDK to be associated with different routers or routes within your service.\n\n### On-Premise Configuration\n\nThe SDK provides a way to redirect the requests it captures to an on-premise deployment of the Speakeasy Platform. This\nis done through the use of environment variables listed below. These are to be set in the environment of your services\nthat have integrated the SDK:\n\n* `SPEAKEASY_SERVER_URL` - The url of the on-premise Speakeasy Platform's GRPC Endpoint. By default this\n  is `grpc.prod.speakeasyapi.dev:443`.\n* `SPEAKEASY_SERVER_SECURE` - Whether or not to use TLS for the on-premise Speakeasy Platform. By default this is `true`\n  set to `SPEAKEASY_SERVER_SECURE=\"false\"` if you are using an insecure connection.\n\n## Request Matching\n\nThe Speakeasy SDK out of the box will do its best to match requests to your provided OpenAPI Schema. It does this by\nextracting the path template used by one of the supported frameworks above for each request captured and attempting to\nmatch it to the paths defined in the OpenAPI Schema, for example:\n\n### Express\n\n```typescript\nconst app = express();\napp.use(speakeasy.expressMiddleware());\napp.all(\"/v1/user/:id/action/:action\", myHandler); // The path template \"/v1/user/{id}/action/{action}\" is captured automatically by the SDK after being normalized to the OpenAPI spec format for paths.\n```\n\n### NestJS\n\n```typescript\n@Controller()\nexport class AppController {\n    constructor(private readonly appService: AppService) {\n    }\n\n    @Get('/v1/user/:id/action/:action') // The path template \"/v1/user/{id}/action/{action}\" is captured automatically by the SDK after being normalized to the OpenAPI spec format for paths.\n    myHandler(): string {\n        // handler code here\n    }\n}\n```\n\nThis isn't always successful or even possible, meaning requests received by Speakeasy will be marked as `unknown`, and\npotentially not associated with your Api, Version or ApiEndpoints in the Speakeasy Dashboard.\n\nThis normally happens if your path contains regex patterns or is a catch all path and your handler parses the routes\nmanually.\n\nTo help the SDK in these situations you can provide path hints per request that match the paths in your OpenAPI Schema:\n\n```typescript\nconst app = express();\napp.use(speakeasy.expressMiddleware());\napp.all(\"/\", (req, res) =\u003e {\n    // Provide a path hint for the request using the OpenAPI Path Templating format: https://swagger.io/specification/#path-templating-matching\n    req.controller.setPathHint(\"/v1/user/{id}/action/{action}\");\n\n    // the rest of your handlers code\n});\n```\n\nThe above example will work for NestJS as well, just get the Speakeasy MiddlewareController from the request object.\n\nNOTE: If using nested Routers in express or Controller path prefixs in NestJS the SpeakeasySDK will not be able to get\nthe full path template for the request due to a [current issue](https://github.com/expressjs/express/issues/2879) in\nexpress. To work around this you can manually set path hints as above or we can monkey patch in a modification to\nexpress to enable the SpeakeasySDK to get the full path template:\n\n```typescript\n/* eslint-disable */\n// @ts-nocheck\nimport express from \"express\";\n\n/* Credit to @watson and @jagadish-kb https://github.com/expressjs/express/issues/2879#issuecomment-269433170 */\n\nconst origUse = express.Router.use;\n\nexpress.Router.use = function (fn) {\n    if (typeof fn === \"string\" \u0026\u0026 Array.isArray(this.stack)) {\n        let offset = this.stack.length;\n        const result = origUse.apply(this, arguments);\n        let layer;\n        for (; offset \u003c this.stack.length; offset++) {\n            layer = this.stack[offset];\n            // I'm not sure if my check for `fast_slash` is the way to go here\n            // But if I don't check for it, each stack element will add a slash to the path\n            if (layer \u0026\u0026 layer.regexp \u0026\u0026 !layer.regexp.fast_slash)\n                layer.__mountpath = fn;\n        }\n        return result;\n    } else {\n        return origUse.apply(this, arguments);\n    }\n};\n\nvar origPP = express.Router.process_params;\n\nexpress.Router.process_params = function (layer, called, req, res, done) {\n    const path =\n        (req.route \u0026\u0026\n            (req.route.path || (req.route.regexp \u0026\u0026 req.route.regexp.source))) ||\n        layer.__mountpath ||\n        \"\";\n    if (req.__route \u0026\u0026 path) {\n        const searchFromIdx = req.__route.length - path.length;\n        if (req.__route.indexOf(path, searchFromIdx) \u003e 0) {\n            return origPP.apply(this, arguments);\n        }\n    }\n    req.__route = (req.__route || \"\") + path;\n\n    return origPP.apply(this, arguments);\n};\n```\n\nCreate a file called `expressmonkeypatch.ts` or similar and import it into your service's `main.ts`\nfile `import \"./expressmonkeypatch\";`. This will path express and allow the SDK to determine the full path\nautomatically.\n\n## Capturing Customer IDs\n\nTo help associate requests with customers/users of your APIs you can provide a customer ID per request handler:\n\n```typescript\nconst app = express();\napp.use(speakeasy.expressMiddleware());\napp.all(\"/\", (req, res) =\u003e {\n    // Provide a path hint for the request using the OpenAPI Path Templating format: https://swagger.io/specification/#path-templating-matching\n    req.controller.setCustomerID(\"a-customers-id\"); // This customer ID will be used to associate this instance of a request with your customers/users\n\n    // the rest of your handlers code\n});\n```\n\nNote: This is not required, but is highly recommended. By setting a customer ID you can easily associate requests with\nyour customers/users in the Speakeasy Dashboard, powering filters in\nthe [Request Viewer](https://docs.speakeasyapi.dev/speakeasy-user-guide/request-viewer-coming-soon).\n\n## Masking sensitive data\n\nSpeakeasy can mask sensitive data in the query string parameters, headers, cookies and request/response bodies captured\nby the SDK. This is useful for maintaining sensitive data isolation, and retaining control over the data that is\ncaptured.\n\nUsing the `Advanced Configuration` section above you can completely ignore certain routes by not assigning the\nmiddleware to their router, causing the SDK to not capture any requests to that router.\n\nBut if you would like to be more selective you can mask certain sensitive data using our middleware controller allowing\nyou to mask fields as needed in different handlers:\n\n```typescript\nimport {Masking} from '@speakeasy-api/speakeasy-typescript-sdk';\n\nconst app = express();\napp.use(speakeasy.expressMiddleware());\napp.all(\"/\", (req, res) =\u003e {\n    ctrl := req.controller;\n    ctrl.setMaskingOpts(Masking.withRequestHeaderMask(\"authorization\")) // Mask the authorization header in the request\n\n    // the rest of your handlers code\n}\n```\n\nThe `Masking` function takes a number of different options to mask sensitive data in the request:\n\n* `Masking.withQueryStringMask` - **withQueryStringMask** will mask the specified query strings with an optional mask\n  string.\n* `Masking.withRequestHeaderMask` - **withRequestHeaderMask** will mask the specified request headers with an optional\n  mask string.\n* `Masking.withResponseHeaderMask` - **withResponseHeaderMask** will mask the specified response headers with an\n  optional mask string.\n* `Masking.withRequestCookieMask` - **withRequestCookieMask** will mask the specified request cookies with an optional\n  mask string.\n* `Masking.withResponseCookieMask` - **withResponseCookieMask** will mask the specified response cookies with an\n  optional mask string.\n* `Masking.withRequestFieldMaskString` - **withRequestFieldMaskString** will mask the specified request body fields with\n  an optional mask. Supports string fields only. Matches using regex.\n* `Masking.withRequestFieldMaskNumber` - **withRequestFieldMaskNumber** will mask the specified request body fields with\n  an optional mask. Supports number fields only. Matches using regex.\n* `Masking.withResponseFieldMaskString` - **withResponseFieldMaskString** will mask the specified response body fields\n  with an optional mask. Supports string fields only. Matches using regex.\n* `Masking.withResponseFieldMaskNumber` - **withResponseFieldMaskNumber** will mask the specified response body fields\n  with an optional mask. Supports number fields only. Matches using regex.\n\nMasking can also be done more globally on all routes or a selection of routes by taking advantage of middleware. Here is\nan example:\n\n```typescript\nimport speakeasy, {Config, Masking} from \"@speakeasy-api/speakeasy-typescript-sdk\";\nimport express from \"express\";\n\nconst app = express();\n\n// Configure the global speakeasy SDK instance\nconst cfg: Config = {\n    apiKey: \"YOUR API KEY HERE\",\t\t\t// retrieve from Speakeasy API dashboard.\n    apiID: \"YOUR API ID HERE\", \t\t\t// custom Api ID to associate captured requests with.\n    versionID: \"YOUR VERSION ID HERE\",\t// custom Version ID to associate captured requests \n    port: 3000,\t\t\t\t\t\t\t// The port number your express app is listening on (required to build full URLs on non-standard ports)\n};\nspeakeasy.configure(cfg);\n\n// Add the speakeasy middleware to your express app\napp.use(speakeasy.expressMiddleware());\napp.use((req: Request, res: Response, next: NextFunction) =\u003e {\n    // Mask the authorization header in the request for all requests served by this middleware\n    ctrl := req.controller;\n    ctrl.setMaskingOpts(Masking.withRequestHeaderMask(\"authorization\"))\n    next();\n});\n```\n\n## Embedded Request Viewer Access Tokens\n\nThe Speakeasy SDK can generate access tokens for\nthe [Embedded Request Viewer](https://docs.speakeasyapi.dev/speakeasy-user-guide/request-viewer/embedded-request-viewer)\nthat can be used to view requests captured by the SDK.\n\nFor documentation on how to configure filters, find\nthat [HERE](https://docs.speakeasyapi.dev/speakeasy-user-guide/request-viewer/embedded-request-viewer).\n\nBelow are some examples on how to generate access tokens:\n\n```typescript\nimport {EmbedAccessTokenRequest} from \"@speakeasy-api/speakeasy-schemas/registry/embedaccesstoken/embedaccesstoken_pb\";\n\n// If the SDK is configured as a global instance, an access token can be generated using the `generateAccessToken` function on the speakeasy package.\nconst req = new EmbedAccessTokenRequest();\nconst filter = new EmbedAccessTokenRequest.Filter();\nfilter.setKey(\"customer_id\");\nfilter.setOperator(\"=\");\nfilter.setValue(\"a-customer-id\");\n\nreq.setFiltersList([filter]);\nconst accessToken = await speakeasy.getEmbedAccessToken(req);\n\n// If you have followed the `Advanced Configuration` section above you can also generate an access token using the `GenerateAccessToken` function on the sdk instance.\nconst req = new EmbedAccessTokenRequest();\nconst filter = new EmbedAccessTokenRequest.Filter();\nfilter.setKey(\"customer_id\");\nfilter.setOperator(\"=\");\nfilter.setValue(\"a-customer-id\");\n\nreq.setFiltersList([filter]);\nconst accessToken = await storeSDK.getEmbedAccessToken(req);\n\n// Or finally if you have a handler that you would like to generate an access token from, you can get the SDK instance for that handler from the middleware controller and use the `GetEmbedAccessToken` function it.\napp.all(\"/\", (req, res) =\u003e {\n    const req = new EmbedAccessTokenRequest();\n    const filter = new EmbedAccessTokenRequest.Filter();\n    filter.setKey(\"customer_id\");\n    filter.setOperator(\"=\");\n    filter.setValue(\"a-customer-id\");\n\n    req.setFiltersList([filter]);\n    const accessToken = await req.controller.getSDKInstance().getEmbedAccessToken(req);\n\n    // the rest of your handlers code\n});\n```\n\n## Developer Portal Tokens\n\nThe Speakeasy SDK can also generate access tokens for\nthe [Developer portal](https://docs.speakeasyapi.dev/docs/integrate-speakeasy/integrate-portal-login/) that\ncan be used to view requests captured by the SDK.\nBelow is an example of how to generate a portal access token:\n\n```ts\n// NestJS\nexport class AuthService {\n    // initialization\n    public async getPortalToken(): Promise\u003cstring\u003e {\n\n        // filter only allows user to view successful requests\n        const filter = new EmbedAccessTokenRequest.Filter();\n        filter.setKey(\"status\");\n        filter.setOperator(\"\u003c\");\n        filter.setValue(\"400\");\n\n        return await getPortalLoginToken(\n            \"\",                             // customerId\n            \"\",                             // display name\n            {email: \"test@example.org\"},    // custom JWT claims\n            {\n                \"end_user:api_keys:read\": true,     // permit reading api keys\n                \"end_user:api_keys:write\": false    // disallow creating api keys\n            },\n            [filter]\n        );\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspeakeasy-api%2Fspeakeasy-typescript-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspeakeasy-api%2Fspeakeasy-typescript-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspeakeasy-api%2Fspeakeasy-typescript-sdk/lists"}