GraphPilot API
The GraphPilot API is the GraphQL API the portal and the gpilot CLI are built on. Scripts and CI
jobs call it directly. This page lists the operations documented for that use; the portal reads
more through it (billing, members, settings), which is not covered here.
| Topic | Where |
|---|---|
| Which permission each operation needs | Permissions |
| Every error code | Codes |
| Operation limits, page sizes, batch sizes, stream lifetimes | Limits |
Endpoint
Section titled “Endpoint”| Transport | Address |
|---|---|
| Queries and mutations | POST https:/, with a JSON body holding query and, where used, variables |
| Subscriptions | wss:/, protocol graphql- |
| Purging without GraphQL | POST https:/, with a JSON body; see purging |
Authentication
Section titled “Authentication”Send an API key as a bearer credential:
Authorization: Bearer <api-key>| Property | Behavior |
|---|---|
| Scheme | Written exactly Bearer, followed by one space. |
| Where keys come from | Created in the portal under the organization’s Settings → API keys. |
| Scope | One organization. Each operation acts in the organization the key belongs to. The one operation that takes an organization argument, deleteOrganization, only accepts that same organization. |
| Permissions | The permissions selected when the key was created. See permissions. |
| Validation cache | A key’s validation result is cached for up to 60 seconds, so a revoked key can take up to a minute to stop working. See how long key changes take. |
| A missing, unknown or unusable credential | See when a credential is refused. |
| Subscriptions | The key travels in the connection_ payload, not in an HTTP header: { "Authorization": "Bearer <api-. Key names are matched case-insensitively. |
curl -sS https://api.graphpilot.io/graphql \ -H "Authorization: Bearer $GRAPHPILOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"{ organization { slug services { subdomain } } }"}'Errors follow the GraphQL response format: an errors array beside data, in an ordinary 200
response, with a code in extensions.code or, for some refusals, extensions.error_code.
Every code is on codes. There are two exceptions. A
credential can be refused before any operation runs (see below). An operation over one of the
API’s operation limits is refused with 400 and
OPERATION_LIMIT_EXCEEDED before it is validated.
When a credential is refused
Section titled “When a credential is refused”How a bad credential is answered depends on what it looks like. A credential that was presented
is never downgraded to an anonymous request: it is either accepted or refused before any
operation runs. Read extensions.code whatever the status is.
| The request carries | Status | What happens |
|---|---|---|
No Authorization header | 200 | The request runs without an identity, and each operation refuses on its own terms: UNAUTHENTICATED, or Insufficient permissions for a read of organization data. |
A value starting with sk_ that is not a usable key: never issued, revoked, rotated or mistyped after the prefix, a key that is not scoped to an organization, or one whose every permission is one an API key may not hold | 401 | Refused by the API before any operation runs, with WWW- and a GraphQL error whose extensions. is UNAUTHENTICATED. The message names the reason, for example “API key not accepted: revoked, rotated or mistyped.” A value that cannot be a key at all (fewer than 8 characters after sk_, more than 512 in all, or a character a bearer credential may not contain) is refused the same way without being looked up, with “API key not accepted: it is not a well-formed key. Check that the whole key was copied.” |
Any other bearer value that does not verify as a sign-in token: a key missing its sk_ prefix, a truncated or malformed value, an expired session token, or Bearer with nothing after it | 401 | Refused by the edge in front of the API before any operation runs, with a GraphQL error whose extensions. is UNAUTHENTICATED and whose message is “The provided token could not be verified.” |
An sk_ key that could not be checked at that moment | 503 | Nothing is said about the key. The response carries Retry-After: 5 and a GraphQL error whose extensions. is SERVICE_. Send the request again after that many seconds. |
An sk_ key GraphPilot has not seen recently, sent while its client is over the validation budget for unrecognized keys | 429 | The key was not checked, so nothing is said about it. The response carries Retry-After with the seconds until the budget allows another check, and a GraphQL error whose extensions. is TOO_. A key the API accepted within the last minute is answered from its cache and is not affected. |
On a subscription, where the key travels in connection_init, the same outcomes close the
WebSocket instead: 4401 for a refusal, 1013 (try again later) for a key that could not be
checked or was not checked for want of budget.
A client that only parses 200 responses meets the 401 on exactly the case a typo in a
configuration file or a revoked key produces. Handle every status.
Finding a service
Section titled “Finding a service”Most operations start from a service. Look one up by its subdomain (the <subdomain> in
https://<subdomain>.<label>.graphpilot.cloud, the value --service takes in the CLI):
query { services(condition: { subdomain: "my-shop" }) { id subdomain name }}services returns a list holding the one service with that subdomain. id is the service’s id
in this API. Every serviceId argument on this page accepts this id; the purge mutations also
accept the subdomain.
Services and organizations
Section titled “Services and organizations”| Operation | Kind | Does |
|---|---|---|
organization | Query | The organization the request is scoped to, or null. |
organizations | Query | Every organization the caller has access to. |
services(condition:) | Query | The organization’s services. |
createService(input: { service: { name, subdomain, originUrl, environment, color }, deploy }) | Mutation | Creates a service. The payload’s signingKey is the service’s signing key in full, the only time it is returned. deploy: true also starts the setup: a first deployment without a schema and without a configuration file, then GraphQL detection. Omitted or false, nothing is deployed. |
classifyServiceOrigin(originUrl:) | Query | Whether the edge could reach an origin URL, decided from the URL alone without calling it: reachableFromEdge, and for a private or local address a reason (PRIVATE_, LOOPBACK_, LINK_, SHARED_, UNSPECIFIED_, MULTICAST_, RESERVED_, LOCAL_ or INVALID_URL) and a message. An IPv4 address carried in an IPv6 one (NAT64, translated, 6to4) is judged as that IPv4 address. |
updateServiceById(input: { id, patch }) | Mutation | Changes a service’s settings and origin, and its schemaSource. |
Service. | Field | Where a deployment takes its schema from when it names none: UPLOAD (the newest upload, the default), NONE (no schema) or INTROSPECT_ (read from the origin through the service’s hostname at every deployment). See schema source. |
Service. | Field | true once a deployment requested by a member or an API key completed, as opposed to the automatic first deployment of the setup. |
requestActionConfirmation(input: { action, subjectId }) | Mutation | Sends the caller a confirmation code by email. Returns sentTo (masked) and expiresAt. |
deleteService(input: { serviceId, confirmationCode }) | Mutation | Deletes a service and tears down its edge infrastructure. Returns Boolean!. |
legalTerms | Query | The terms in force: version, url and privacyPolicyUrl. Answered without a credential. |
createOrganization(input:) | Mutation | Creates an organization. Refused for an API key. Requires termsAcceptance: { termsVersion } naming legalTerms., see terms acceptance. A billing account funds at most 3 organizations; a fourth is refused with ORGANIZATION_. |
updateOrganization(input: { organizationId, name, slug, domains, websiteUrl, industry }) | Mutation | Changes the caller’s current organization. organizationId must name it; every other field is optional. |
deleteOrganization(organizationId:, confirmationCode:) | Mutation | Deletes the caller’s current organization. Returns Boolean!. |
deleteMyAccount(input: { confirmationCode }) | Mutation | Starts deleting the caller’s own account; the deletion completes in the background. Returns Boolean!. See your account. |
Service.url, Service. | Field | The hostname the service answers on: url as https:// plus the hostname, primaryDomain as its ServiceDomain. The service hostname until a custom domain is made primary with setPrimaryDomain. |
Organization., accountLockedAt, accountLockDueAt, accountTerminationDueAt, accountTerminatedAt | Field | The state of the billing account that funds the organization, readable without billing access: why and since when it is locked (PAYMENT_ or MANUAL), and for an overdue payment the day it is locked, the day the paid plan may be terminated, and when it was. null when they do not apply. |
Terms acceptance
Section titled “Terms acceptance”Creating an organization and ordering a paid plan each accept the terms in force, and the API
refuses both without that acceptance. legalTerms.version is the version to name; any other is
refused, so read it again after the terms change.
| Operation | Input | Required |
|---|---|---|
createOrganization | termsAcceptance: { termsVersion } | Always. |
subscribePlan | termsAcceptance: { termsVersion, actsAsBusiness, companyName } | For a paid plan. actsAsBusiness must be true (the customer orders for a company or as a self-employed professional, a business in the sense of § 14 BGB). companyName is optional. Ignored for the free plan. |
A refusal changes nothing. Without an acceptance, or with another version, the error is
TERMS_NOT_ACCEPTED, with extensions.reason set to missing or outdated and
extensions.currentVersion naming the version to accept. Without the business confirmation it is
BUSINESS_CONFIRMATION_REQUIRED, with extensions.reason set to not_confirmed. Each accepted
request is recorded with the version, the time and the user, by id and with the email address and
name of the user’s login at that moment; a paid order before the order is sent. If the user’s
details cannot be read, the request fails and nothing is created or ordered.
Invoices are addressed to the name on the billing account’s billing address
(BillingAddress.companyName). A paid order with a companyName that is not blank replaces that
name before the order is sent, and if that fails, the request fails and nothing is ordered. Without
one, or with a blank one, the billing address keeps its name.
Confirmations
Section titled “Confirmations”Deleting a service, an organization or your account needs a code sent by email.
| Rule | Detail |
|---|---|
| Actions | DELETE_, DELETE_, DELETE_ (the action of requestActionConfirmation). |
| Who | An interactive user only. An API key is refused with FORBIDDEN, both when requesting and when spending a code. |
| Authorization | Requesting a code runs the same checks as the action itself: a subject the caller cannot see is NOT_FOUND. |
| Lifetime | A code expires after 10 minutes and is spent by the action it confirms, so it works once. |
| Attempts | 5 per code. Every attempt counts, a correct one included; from the sixth on, even the right code is refused with INVALID_. Request a new code. |
| A new code | Replaces the live code for the same action and subject: the earlier one stops working. |
| Rate limit | At most 3 codes per user per 60 seconds, counted across all three actions (TOO_). |
| A wrong code | INVALID_, whether it was never issued, expired, out of attempts or mistyped. |
Deployments
Section titled “Deployments”A deployment builds from the schema and configuration last uploaded for the service, unless it names other versions or asks for none.
| Operation | Kind | Does |
|---|---|---|
createSchemaUploadUrl(serviceId:) | Mutation | A signed URL. Upload the schema with PUT and Content-. The response’s x- header is the version. |
createConfigUploadUrl(serviceId:) | Mutation | The same for the configuration, with Content-Type: application/toml. |
createConfigDownloadUrl(serviceId:) | Mutation | A signed URL to GET the stored configuration. NOT_FOUND if none was uploaded. |
Service., Service. | Field | version, md5, crc32c, size, createdAt, and commitHash and commitMessage when the upload sent them as x- and x-. |
createDeployment(input: { serviceId, schemaVersion, withoutSchema, configVersion, withoutConfig, forceBuild, coreVersion }) | Mutation | Starts a deployment. An omitted schema version follows the service’s schemaSource (the latest upload by default); an omitted config version takes the latest upload. withoutSchema: true deploys without a schema, as a plain HTTP service with the GraphQL features off, and records a null schema version; it cannot be combined with schemaVersion. withoutConfig: true deploys without a configuration file, every setting at its default, and records a null config version; it cannot be combined with configVersion (CONFIG_). forceBuild rebuilds even when a cached build exists. coreVersion is a runtime version; omitted, the service’s pin is used, else the stable version. For a service that introspects at deploy, refused with ASSET_ when an upload of the same file landed while GraphPilot was writing it; nothing is written, so send it again. Returns deployment. |
cancelDeployment(input: { deployment }) | Mutation | Cancels a deployment in STARTED or PENDING. Otherwise INVALID_. Returns result. |
destroyDeployment(input: { serviceId }) | Mutation | Tears down the service’s deployed edge infrastructure, keeping the service, which can be deployed again. Runs asynchronously; returns success and service. Deleting a service does this too. |
deploymentProgress(deploymentId:) | Query | The deployment’s progress, once. |
deploymentProgress(deploymentId:) | Subscription | The same, sent on connect and again on every change. |
Service. | Field | The schema the service’s most recent completed deployment was built from. null if it was never deployed or deployed without a schema. |
Deployment., Deployment. | Field | The schema and the configuration a deployment was built from. null when the deployment pinned none. configDocument needs service:edit, like createConfigDownloadUrl, because a configuration can hold a provider’s shared secret: without it the field alone is refused with FORBIDDEN and the rest of the query answers. schemaDocument needs only deployment:view, and configAnalysis stays readable with secrets redacted. |
Deployment., Deployment. | Field | The configuration generation the deployment pinned, null for a deployment without a configuration file, for which usesDefaultConfig is true. Its configAnalysis still lists every setting, each with source: default. |
Service. | Field | The effective defaults: the configuration report of the service’s newest completed deployment without a configuration file, the same shape as configAnalysis. null when there is none. |
Deployment., Deployment. | Field | Who asked for the deployment: requestedBy is a person or an API key, null when nobody was recorded. For a deployment GraphPilot requested itself, requestedBy is null and requestedByPlatform names why: SERVICE_ for the automatic first deployment of the setup. requestedByPlatform is null for every other deployment. |
Deployment., Deployment. | Field | Where the deployment’s schema came from: UPLOAD, INTROSPECTION or NONE (null for deployments from before this was recorded). For a service that introspects at deploy, schemaIntrospection has succeeded, path, error and fallbackSchemaFrom, the upload time of the schema used instead when introspection failed (null when there was none, and the deployment then has no schema). |
Deployment. | Field | What changed against the schema that was live when the deployment was requested: previousSchemaVersion, addedTypes, removedTypes, addedFields and removedFields (as Type.field), and a summary such as +3 types, -1 field or No changes. null when either side has no schema. |
Deployment. | Field | Why the deployment ended without going live. For FAILED, the failure (see deployment failures). For CANCELLED, the reason when GraphPilot canceled the run: Replaced by a newer deployment of this service before it went live. when a newer deployment of the service replaced it, Cancelled before it went live. otherwise; null when the cancellation was requested, as with cancelDeployment. null for every other status. |
Service. | Field | The service’s deployments, newest first, with status (STARTED, PENDING, COMPLETED, FAILED or CANCELLED), diagnostics and configAnalysis. |
DeploymentProgress field | Meaning |
|---|---|
deploymentId | The deployment id. |
status | RUNNING, COMPLETED, FAILED or CANCELLED. |
steps | Each step’s id, name, status (PENDING, RUNNING, COMPLETED, FAILED, SKIPPED), startedAt, completedAt and error. |
progress | total, completed and percentage of steps. |
timestamp | Unix time in milliseconds. |
query { services(condition: { subdomain: "my-shop" }) { deployments(first: 1) { id status createdAt diagnostics { origin source severity message key line column } configAnalysis { unknown { path line } inert { path line } } } }}Deployment.diagnostics
Section titled “Deployment.diagnostics”What the build found wrong in your schema and configuration without refusing the deployment.
| Field | Type | Meaning |
|---|---|---|
origin | String! | Which document the finding is about: schema or config. |
source | String! | Which check produced it, such as cache_, surrogate_ or auth. |
severity | SchemaDiagnosticSeverity! | ERROR (what you wrote has no effect), WARNING (it works as written, probably not as meant) or INFO (a notice, nothing to fix: for example that a deployment has no schema). None of them fails the deployment. |
message | String! | The finding, in words. |
key | String | For a configuration finding, the key it is about, such as client.. null for a schema finding. |
line | Int | One-based line in the schema. null where the finding has no position, and always null for a configuration finding. |
column | Int | One-based column in the schema, on the same terms as line. |
null for the whole list means nothing was recorded: the deployment predates stored diagnostics
or never got as far as building. An empty list means the build found nothing. origin and key
read schema and null on records written before those fields existed. What each source
reports is under deployments.
Deployment.configAnalysis
Section titled “Deployment.configAnalysis”| Field | Type | Meaning |
|---|---|---|
unknown | [ConfigKeyReference!]! | Keys your configuration writes that nothing reads, usually a misspelling. |
inert | [ConfigKeyReference!]! | Keys that are valid and read by nothing, reported only where you wrote them. |
settings | [ConfigSetting!]! | Every setting the configuration resolved to, sorted by path, defaults included. |
config | String! | The file name the configuration was read from. |
version | Int! | The shape of the stored report. |
Each ConfigSetting has a path (such as client.profile[0].max_age), a value (JSON, null
when redacted), a source (explicit when your configuration names the path, default when it
does not) and redacted (true when the value is withheld). Service.configAnalysis returns the
same report for the deployment the service runs now.
Each ConfigKeyReference has a path (the key) and a line (one-based, in the configuration file
the deployment was built from). configAnalysis is null for a build with no configuration
report, such as one older than 90 days.
Service setup
Section titled “Service setup”The setup a service created with deploy: true goes through, the same one the portal shows as
a card on the service’s dashboard and gpilot service create walks through. Poll Service.setup about every three seconds while state is
DEPLOYING, WAITING_FOR_CERTIFICATE, DETECTING or APPLYING.
| Operation | Kind | Does |
|---|---|---|
Service. | Field | The setup, or null for a service created without it. |
retryServiceSetupDetection(input: { serviceId }) | Mutation | Probes the origin again (state DETECTING). Needs deployment:edit. Starts a setup for a service that has none, once a deployment of it completed (otherwise SERVICE_). |
applyServiceSetupSuggestion(input: { serviceId }) | Mutation | Uploads the suggested schema and, when it is not the default, the suggested configuration, and starts a deployment with them, requested by the caller (state APPLYING). Only in SUGGESTION_ and with a schema (SERVICE_ otherwise). Never replaces files of your own: refused with SETUP_ or SETUP_ when the service’s newest configuration or schema upload was not written by the setup; canApplySuggestion does not reflect this. Refused with ASSET_ when an upload of the service’s configuration or schema landed while GraphPilot was writing it; nothing is written and the setup stays in SUGGESTION_, so apply again. Needs deployment:edit. Returns setup and deployment. |
keepServiceAsPlainHttp(input: { serviceId }) | Mutation | Closes the setup and leaves the service as it is (state DONE, outcome PLAIN_HTTP). Not while something is running. Needs service:edit. |
A mutation the current state does not allow is refused with SERVICE_SETUP_STATE_CONFLICT; the
setup’s canRetryDetection, canApplySuggestion and canKeepAsPlainHttp say which are allowed.
A setup does not stay in APPLYING or DETECTING: a step that cannot finish ends in FAILED
with SETUP_INTERRUPTED.
ServiceSetup field | Meaning |
|---|---|
state | CREATED, DEPLOYING, WAITING_, DETECTING, SUGGESTION_ (GraphQL found), NO_, ORIGIN_ (the edge could not reach the origin), SKIPPED_ (a private or local origin, not deployed), APPLYING, DONE or FAILED. |
outcome | For DONE: GRAPHQL (the suggestion went live), PLAIN_HTTP (kept as plain HTTP) or OWN_ (a deployment of the caller’s own replaced the setup). |
message | A sentence for the current state. |
errorCode | For FAILED, ORIGIN_, NO_ and SKIPPED_: NOT_, PRIVATE_, DEPLOYMENT_, CERTIFICATE_, CERTIFICATE_ (the certificate was still pending after 60 minutes), ORIGIN_, NO_, DETECTION_, SETUP_ (a step stopped before it could finish, for example an apply that got no deployment within 10 minutes; retry the detection or keep plain HTTP), ACCOUNT_ or BEING_ (the first deployment was not requested because the billing account is locked or the organization or account is being deleted). |
initialDeployment, appliedDeployment | The automatic first deployment, and the one applyServiceSetupSuggestion started. |
detection | graphqlPath (the path that answered { __typename }), originUnreachable (no probe got an answer from the origin), introspectionAvailable, introspectionError, attempts, and the probes, each with path, status, result and durationMs. result is GRAPHQL, NOT_GRAPHQL (the origin answered, but not as GraphQL, including its own 5xx), UNREACHABLE (the edge’s own 502 with BAD_GATEWAY, or no answer), REFUSED (the edge refused GraphPilot’s probe; the setup is then FAILED with DETECTION_) or NOT_TRIED. |
suggestion | graphqlPath, configDocument (the gpilot.toml it deploys, null for the defaults), schemaDocument (the schema read by introspection, null without one) and typeCount. |
createdAt, stateChangedAt, history | When the setup started and last changed state, and every state it passed through with its time and message. |
A service created with deploy: true by a caller who may not create deployments is created, and
its setup is FAILED with NOT_ALLOWED_TO_DEPLOY. Creating the service never fails because the
setup could not be started; the service then has setup: null. The service hostname is
Service.url.
Runtime versions
Section titled “Runtime versions”The catalog of runtime versions a service can be built against. The two queries are answered without a credential.
| Operation | Kind | Does |
|---|---|---|
runtimeVersions(includeYanked: Boolean = false) | Query | Every version, newest first. Withdrawn versions only with includeYanked: true. |
runtimeChangelog(from:, to:) | Query | The versions released after from, up to and including to (default: the stable version), newest first, withdrawn ones included. |
Service. | Field | The version the service is pinned to. null follows the stable version. |
Service. | Field | The version the active deployment was built with. null for a service never deployed. |
Service. | Field | The version the next deployment is built with: the pin, else the stable version. null while the pin names a withdrawn version. |
setServiceRuntimePin(input: { serviceId, version, deployNow }) | Mutation | Pins the service to version, or with version: null removes the pin. deployNow (default true) rebuilds the service with the version the pin resolves to; false saves the pin alone, and the service’s next deployment uses it. Even with deployNow: true, no deployment starts when the live deployment already runs that version and no deployment is in progress. Returns service, resolvedVersion (the pinned version, or the stable version for no pin), outcome and deployment. outcome is DEPLOYMENT_, ALREADY_, DEPLOYMENT_ (deployNow: false) or NEVER_ (the service’s first deployment uses the pin); deployment is the new deployment for DEPLOYMENT_ and null otherwise. Removing the pin while no stable version exists is refused with PRECONDITION_ (No runtime version is on channel stable yet). |
RuntimeVersion field | Meaning |
|---|---|
version | The name to pin. |
status | ACTIVE (offered), DEPRECATED (still served, no longer offered) or YANKED (withdrawn). |
releasedAt | When the version was made available. |
yankedAt, yankReason | When and why it was withdrawn. null unless YANKED. |
notes | Release notes, in Markdown. Empty when there are none. |
channels | The channels that point at it now, such as stable. |
Purging
Section titled “Purging”Four mutations purge a service’s cache. All take a serviceId (the id or the subdomain) and
return the same PurgePayload. Every failure is a GraphQL error rather than a payload with
success: false.
| Mutation | Addresses |
|---|---|
purgeBySurrogateKey | One or more surrogate keys, or a cache key written with its ck: prefix |
purgeByQueryHash | A query, optionally narrowed to one variable set |
purgeByRequest | The cache entry one telemetry request read or wrote |
purgeAll | Everything the service has cached |
mutation { purgeBySurrogateKey(input: { serviceId: "my-shop" keys: ["Product:id:42"] }) { purgedKeyCount purgedKeys }}purgedKeyCount counts keys, not cache objects. Inputs, soft purges and failure modes are in
purging through the API.
purgeBySurrogateKey and purgeAll can also be sent without GraphQL, to POST /purge on the same
host. It runs the mutation with the same credential and permission, answers 200 with the
PurgePayload as the body, and answers a refusal with a matching HTTP status and the same
errors list. The body forms and the status for each code are under over
REST.
curl -sS https://api.graphpilot.io/purge \ -H "Authorization: Bearer $GRAPHPILOT_API_KEY" \ -H "Content-Type: application/json" \ -d '{"serviceId":"my-shop","keys":["Product:id:42"]}'Service.purges
Section titled “Service.purges”Every invalidation of a service’s cache, automatic and manual, newest first. See verifying a purge. The history is request telemetry, stored and kept under the rules on what Insights needs.
query { services(condition: { subdomain: "my-shop" }) { purges( first: 20 timeRange: { from: "2026-09-22T00:00:00Z", to: "2026-09-23T00:00:00Z" } filter: { trigger: [MANUAL] } ) { nodes { id timestamp trigger soft keys keyCount error actor { email } } pageInfo { hasNextPage endCursor } } }}| Argument | Type | Meaning |
|---|---|---|
timeRange | TimeRangeInput! | Required. from and to as ISO 8601 timestamps, both inclusive. Clipped to what your plan retains; a window entirely older returns an empty page. |
first | PositiveInt | Page size. Default 20, at most 1000. |
after | String | The endCursor of the previous page. |
filter | PurgesFilterInput | Optional. trigger (AUTO, MANUAL), scope (EVERYTHING, KEYS), soft, outcome (SUCCEEDED, FAILED), key (at least one key containing this text, matched literally) and actorUserIds. Fields combine with AND. |
PurgeEntry field | Type | Meaning |
|---|---|---|
id | ID! | The entry’s id. |
timestamp | DateTime! | When the purge ran. |
trigger | PurgeTrigger! | AUTO for a purge caused by a mutation, MANUAL for one sent through the API, the CLI or the portal. |
soft | Boolean! | true when entries were marked stale rather than removed. |
keys | [String!]! | The surrogate keys addressed. Empty for a purge of everything. |
keyCount | Int! | How many keys were addressed, not cache objects. 0 for a purge of everything. |
error | String | null when no error was recorded. Otherwise the cache is known to be wrong, and for a keyed purge an unknown part of the keys may already have been purged. The value is a fixed message, not the edge’s own failure text. |
actor | User | The member who sent a manual purge. null for an automatic purge, for a purge sent with an API key (which is not recorded under a user id), and for a user who no longer exists. |
triggeredByRequest | RequestEntry | For an automatic purge, the mutation request that caused it, while it is within telemetry retention. |
targetRequest | RequestEntry | For a purge addressed by request id, the request named, while it is within telemetry retention. |
Persisted queries
Section titled “Persisted queries”See persisted queries for how the registry is used at the edge.
| Operation | Kind | Does |
|---|---|---|
pushPersistedQueries(input: { serviceId, documents: [{ hash, document }] }) | Mutation | Registers manifest documents. Additive and idempotent: nothing is removed, and re-sending an entry is a no-op. Each hash is the hex SHA-256 of its document and is verified. |
removePersistedQueries(input: { serviceId, hashes }) | Mutation | Revokes operations: deletes the registry entries and purges everything cached for them. Clients still sending these hashes break. |
Service. | Field | The manifest: every pushed operation, with usage(startTime, endTime). |
Service. | Field | How many operations the manifest declares, revoked ones excluded. |
Service. | Field | Operations clients registered over APQ that the manifest does not declare, one page of hashes at a time. |
Service. | Field | One registry entry by hash, or null, with origin (APQ or PUSHED). |
| Result | Fields |
|---|---|
pushPersistedQueries | results, one per document in the order sent: hash, status (ADDED, ALREADY_, ADOPTED, REJECTED) and reason for a rejection; and warning, non-null when the service’s deployed configuration is not known to turn persisted queries on. A REJECTED entry does not fail the batch. |
removePersistedQueries | results, one per hash: removed (the registry held it and it was deleted), purged (everything cached for it was cleared; false means repeat the call for that hash) and recorded (the withdrawal was written to your manifest). |
Telemetry
Section titled “Telemetry”The request telemetry behind Insights. Every list takes a required timeRange,
clipped to what your plan retains, and a filter (RequestsFilterInput); a filter or a sort your
plan does not include is refused with FORBIDDEN.
| Operation | Kind | Does |
|---|---|---|
Service. | Field | Requests, newest first. The connection’s analytics carries timeSeries(groupBy, granularity, topGroups), metrics(granularity), summary and top(limit). |
Service. | Field | One request by id. |
Service., Service. | Field | The same for GraphQL operations. |
Service. | Field | Failures grouped by groupBy. |
Service. | Field | Traffic by client. |
Service. | Field | Values seen for a filter field within the plan’s telemetry retention, for autocomplete. limit defaults to 20 and is clamped to 100. |
Service. | Field | The service’s log lines. |
serviceRequestsStream(serviceId, after, filter) | Subscription | New requests as they are recorded. Without after, only entries arriving after the subscription starts. |
serviceOperationsStream(serviceId, after, filter) | Subscription | The same for GraphQL operations. |
serviceLogsStream(serviceId, after, level, target, requestId) | Subscription | New log lines. |
A request carries two ids. RequestEntry.id is its identity in GraphPilot, the one
Service.request(id:), gpilot requests and the portal’s Entry ID use.
RequestEntry.edgeRequestId is the edge platform’s own id for the request (Fastly’s request id),
for correlating it with the edge platform’s logs, for example in a support case. It is visible on
every plan, and null on a request recorded before GraphPilot stored it.
A request stream polls for new entries and closes itself after 5 minutes without one; a log stream
closes after 30 minutes. Resubscribe with the last cursor as after to continue. Subscriptions
authenticate in connection_init (see authentication).
Signing key
Section titled “Signing key”| Operation | Kind | Does |
|---|---|---|
Service., Service. | Field | The active and the pending key, redacted: gpsk_, 24 bullets and the key’s last four characters. null without service:edit (and always for an API key), or when there is none. |
createService payload signingKey | Field | The key a new service is issued, in full. The only time it is returned. |
rotateServiceSigningKey(input: { service }) | Mutation | Generates a pending key. The payload’s pendingSigningKey is the key in full, the only time it is returned. |
cancelServiceSigningKeyRotation(input: { service }) | Mutation | Discards the pending key. |
activateServiceSigningKey(input: { service }) | Mutation | Makes the pending key the active one. |
service is the service’s id. How rotation works is on request
signing.
Custom domains
Section titled “Custom domains”| Operation | Kind | Does |
|---|---|---|
addServiceDomain(input: { serviceId, fqdn }) | Mutation | Attaches a hostname and starts its verification. Needs a paid plan and a domain your organization has verified. Returns the ServiceDomain. |
ServiceDomain. | Field | The DNS records to create for verification. |
ServiceDomain. | Field | For a service platform hostname that gets a certificate of its own: PENDING while it is issued, ISSUED once the hostname serves TLS, FAILED when issuance gave up. null for every other hostname. |
retryDomainVerification(id:) | Mutation | Retries verification of a failed domain. Returns the ServiceDomain. |
setPrimaryDomain(id:) | Mutation | Makes an active domain the service’s primary hostname. Returns the Service. |
removeServiceDomain(id:) | Mutation | Detaches a domain. Starts a deployment that takes the hostname off the edge; the service keeps answering on it until that deployment finishes. Returns the Service. |
enablePlatformDomain(serviceId:), disablePlatformDomain(serviceId:) | Mutation | Turns the <subdomain>. hostname on or off. It can be disabled, not removed, and only while the service has another active domain. Disabling also turns off an older <subdomain>. kept beside it while a service is moved onto its label; enabling turns on only the current one. Returns the Service. |
See custom domains for plans and verification.
Service.ipRanges
Section titled “Service.ipRanges”The IP ranges Fastly’s edge network reaches your origin from, for an origin allowlist, which also has the example query and why to re-read them.
| Field | Type | Meaning |
|---|---|---|
ipv4 | [String!]! | IPv4 ranges in CIDR notation. |
ipv6 | [String!]! | IPv6 ranges in CIDR notation. |
Query.clientIp
Section titled “Query.clientIp”clientIp: String is your public IP address as GraphPilot’s edge saw the request, IPv4 or IPv6.
It answers only a signed-in caller (a person or an API key) and is null for an anonymous one,
and null too when the edge reported no address. It carries no cache lifetime, so no response
holding it is stored. gpilot requests --ip reads it. It is not affected by telemetry.client_ip, which changes what Insights stores: on a service that sets it to "truncated" or "none", RequestClient.ip is the truncated address or null, and the geo and network fields that setting drops are null (utcOffset reads 0).
Related
Section titled “Related”- API keys for creating keys and choosing their permissions.
- Purging through the API for the purge mutations in full.
- Deployments for what the diagnostics mean.
- Origin allowlist for keeping a firewall rule current.