ctx.http is a ky instance for outbound HTTP. Call it directly for plain requests, or call ctx.http.authed(alias) to route the request through the Helix proxy, which injects credentials server side so secrets never reach your code. For an AWS S3 credential, authed(alias).s3Sign() returns a presigned object URL for direct uploads and downloads. ctx.auth(alias) returns the non-sensitive variables of a credential record.
ctx.http: a ky instance
Everything ky supports works on ctx.http: get, post, put, patch, delete, head, the json: request option, .json<T>() on responses, retries, timeouts, extend(), and the beforeRequest/afterResponse/beforeRetry hooks.
const data = await ctx.http
.get('https://api.open-meteo.com/v1/forecast', {
searchParams: { latitude: 51.5, longitude: -0.1 },
retry: { limit: 3, backoffLimit: 3000 },
timeout: 10_000,
})
.json();
Unauthenticated calls go directly to the target but are still logged and traced.
ctx.http.authed(alias)
authed(alias: string): KyInstance
| Parameter | Type | Description |
|---|---|---|
alias | string | A key from authentications in helix.config.ts, mapping to a credential UUID. An unknown alias throws an error listing the available aliases. |
The returned instance is standard ky. Every request is routed through the Helix proxy, which resolves the credential for that alias, injects it server-side (Bearer for OAuth 2.0, or a named header for API Token), and forwards the call. Because it’s plain ky, you can extend() it with a prefixUrl or default headers.
Use a full target URL in the request. If an OAuth token has expired or the target returns 401, the proxy refreshes the token and retries once. Every request and response is logged with credentials redacted. Credential setup and the auth model are covered in the connected services guide.
authed(alias).s3Sign(url, options)
For an AWS S3 credential, s3Sign returns a presigned S3 URL: a time-limited URL that grants access to one object, with no credentials attached. Hand it to a browser, another service, or your own code, and the transfer goes directly to S3 rather than through your function, which makes it the right tool for large uploads and downloads.
s3Sign(url: string, options?: S3SignOptions): Promise<S3SignResult>
| Parameter | Type | Description |
|---|---|---|
url | string | The full https: object URL, either https://<bucket>.s3.<region>.amazonaws.com/<key> or https://s3.<region>.amazonaws.com/<bucket>/<key>. |
options.method | 'GET' | 'PUT' | 'POST' | 'DELETE' | 'HEAD' | The HTTP method the URL is signed for. Defaults to GET. The URL only works with this method. |
options.expiresIn | number | Seconds until the URL expires. Defaults to 900 (15 minutes); the maximum is 604800 (one week). |
options.timeout | number | Per-call timeout in milliseconds. Defaults to 30000. |
The result is { url, method, expiresAt }, where expiresAt is the ISO 8601 instant the URL stops working.
// functions/api/v1/report-link.get.ts
import { defineFunction } from '@trayai/helix-sdk';
export default defineFunction(async (ctx) => {
const aws = ctx.http.authed('aws_s3');
// A download link, valid 15 minutes:
const download = await aws.s3Sign(
'https://my-bucket.s3.eu-west-1.amazonaws.com/reports/summary.pdf',
);
// An upload link, valid one hour:
const upload = await aws.s3Sign(
'https://my-bucket.s3.eu-west-1.amazonaws.com/incoming/video.mp4',
{ method: 'PUT', expiresIn: 3600 },
);
return { downloadUrl: download.url, uploadUrl: upload.url, expiresAt: download.expiresAt };
});
Signing works with AWS S3 credentials only; an alias for any other service is rejected with a 400 error. The URL is a live grant on the credential until it expires, so treat it like a secret: return it to the caller who needs it, and pick the shortest expiresIn that fits the job.
ctx.auth(alias)
auth(alias: string): Promise<Record<string, string>>
Returns only the non-sensitive variables of the credential record, for use in logging, conditional logic, or constructing non-HTTP resources. Tokens, API keys, and other secrets are never returned; the platform decides which fields are safe based on the credential record’s configuration.
const vars = await ctx.auth('salesforce_prod');
// { instance_url: 'https://mycompany.my.salesforce.com', subdomain: 'mycompany' }
Example
// functions/api/v1/contacts.get.ts
import { defineFunction } from '@trayai/helix-sdk';
export default defineFunction(async (ctx) => {
const sf = ctx.http.authed('salesforce_prod').extend({
prefixUrl: 'https://acme.my.salesforce.com/services/data/v59.0',
});
const result = await sf
.get('query', { searchParams: { q: 'SELECT Id, Name, Email FROM Contact' } })
.json<{ records: Array<{ Id: string; Name: string; Email: string }> }>();
return result.records;
});