# Use the GraphQL API

Call the Origin Cloud GraphQL API with a bearer token, find operations by namespace, read resource URNs, and handle typed enums and errors.

The GraphQL API is the complete interface to Origin Cloud: the console and the `origin` CLI use it too. Call it directly for automation, integrations, and operations the CLI doesn’t cover.

## Before you begin [#before-you-begin]

<BeforeYouBegin>

- A user account, with the `origin` CLI installed and logged in, or a service account with its client ID and secret. See [Use the CLI](/docs/platform/access/cli) and [Service accounts](/docs/iam/service-accounts).
- An HTTP client, such as `curl`, or a GraphQL client library.

</BeforeYouBegin>

## Endpoint [#endpoint]

Every request goes to one endpoint:

```text
https://api.origincloud.eu/graphql
```

Send queries and mutations as an HTTP `POST` with a JSON body that holds `query` and, optionally, `variables`. The API supports GraphQL introspection, so code generators and IDE plugins can read the schema from the endpoint with a valid token.



## Authenticate [#authenticate]

Every request carries an access token as a bearer token in the `Authorization` header:

```text
Authorization: Bearer <access-token>
```

A request without a token, or with an expired or invalid one, fails with the error code `UNAUTHORIZED`. Get a token in one of two ways:

- As yourself: log in with the CLI, then print the token with `origin id token --raw`. The CLI renews it when it expires. See [Use the CLI](/docs/platform/access/cli).
- As a service account: request a token with the OAuth 2.0 client credentials grant, using the service account’s client ID and secret. See [Service accounts](/docs/iam/service-accounts).

Access tokens are short-lived. When a request fails with `UNAUTHORIZED`, get a new token and send the request again.

## Send a request [#send-a-request]

1. Write the query. This one lists the organizations you can access:

   ```graphql
   query {
     admin {
       organisations {
         orgId
         name
         status
       }
     }
   }
   ```

1. Send it with your token:

   ```sh
   curl -sS https://api.origincloud.eu/graphql \
     -H "Authorization: Bearer <access-token>" \
     -H "Content-Type: application/json" \
     -d '{"query":"{ admin { organisations { orgId name status } } }"}'
   ```

1. Verify the response. A successful response has a `data` object and no `errors` array. Example output (illustrative):

   ```json
   {
     "data": {
       "admin": {
         "organisations": [
           { "orgId": "0a1b2c3d4e5f", "name": "Example GmbH", "status": "ACTIVE" }
         ]
       }
     }
   }
   ```

Pass values through variables rather than pasting them into the query text. That avoids quoting problems:

```json
{
  "query": "query($org: OrgId!) { admin { organisation(orgId: $org) { name status } } }",
  "variables": { "org": "0a1b2c3d4e5f" }
}
```

## Namespaces [#namespaces]

Operations are grouped by service. Every query and mutation sits under one of these top-level fields:

| Namespace | Queries | Mutations | Covers |
| --- | --- | --- | --- |
| `admin` | yes | yes | Organizations, projects, billing accounts, quotas, usage and cost, support cases |
| `iam` | yes | yes | Members, invites, roles, permissions, service accounts, audit log |
| `compute` | yes | yes | Instances, instance types, images, image families, key pairs |
| `pvs` | yes | yes | Volumes, snapshots, storage classes |
| `network` | yes | yes | VPCs, subnets, network interfaces, gateways, Floating IPs, route tables, security groups, network ACLs, DNS |
| `observability` | yes | no | Metrics |

For example, launching an instance is `mutation { compute { launchInstance(...) { ... } } }`.

## Resource URNs [#resource-urns]

Every resource has a URN, a globally unique identifier returned in its `urn` field. Compute, storage and network operations take URNs as input, such as `projectUrn`, `instanceUrn` or `subnetUrn`. Organization and IAM operations take plain IDs, such as `orgId` and `projectId`.

A URN has eight colon-separated parts:

```text
urn:origin:cloud:<service>:<region>:<org-id>:<project-id>:<resource-id>
```

| Part | Meaning |
| --- | --- |
| `urn:origin:cloud` | A fixed prefix. |
| `<service>` | The service that owns the resource: `admin`, `iam`, `compute`, `pvs`, `network` or `observability`. |
| `<region>` | The region the resource lives in, such as `eu-central1`. Empty for resources that aren’t bound to a region. |
| `<org-id>` and `<project-id>` | The organization and project that own the resource. Empty where they don’t apply. |
| `<resource-id>` | The resource’s own ID within the service. |

Examples:

| Resource | URN |
| --- | --- |
| Organization | `urn:origin:cloud:admin::::0a1b2c3d4e5f` |
| Project | `urn:origin:cloud:admin::0a1b2c3d4e5f::demo-48291037561` |
| Instance | `urn:origin:cloud:compute:eu-central1:0a1b2c3d4e5f:demo-48291037561:i-79PVin5MmNc` |
| Built-in role | `urn:origin:cloud:iam::::tc/role/roles/viewer` |

Copy a URN from the `urn` field of a response rather than assembling it yourself. The one URN you often need without having it at hand is a project’s: it’s `urn:origin:cloud:admin::<org-id>::<project-id>`. The API returns it as the project’s `urn` field, and `origin admin create-project` prints it, but `origin admin get-project` and `list-projects` don’t.

## Typed enums [#typed-enums]

Statuses and other closed sets of values are GraphQL enums, not free text. Examples are an organization’s `status` (`PENDING_REVIEW`, `ACTIVE`, `REJECTED`), a billing account’s `paymentMethodStatus`, and an instance’s `status`.

- Generate your client types from the schema. A typed client lists every value the schema defines, and fails to compile when a value is added that your code doesn’t handle.
- Compare against the enum, not against strings copied from a response.
- Handle a value your code doesn’t recognize explicitly, for example by surfacing it, rather than mapping it to a default.

## Lists and pages [#lists-and-pages]

Most list queries return a plain list. A few queries that can return many entries, such as the audit log and support cases, return a page instead: the entries plus `total`, `hasMore`, `offset` and `limit`. Read the next page by adding `limit` to `offset`, while `hasMore` is `true`. For page size limits, see [Limits](/docs/platform/reference/limits).

## Errors [#errors]

A failed operation returns an `errors` array. Each error has a `message` and, in `extensions`, a stable `code`, a `retryable` flag and a `correlationId`:

```json
{
  "errors": [{
    "message": "invalid input on field sizeInGib: must be at least 1",
    "extensions": {
      "code": "BAD_REQUEST",
      "retryable": false,
      "correlationId": "4bf92f3577b34da6a3ce929d0e0e4736"
    }
  }]
}
```

Branch on `code`, never on the message text: codes are stable, messages can change. For every code and what to do about it, see [Error codes](/docs/platform/reference/errors).

## Related [#related]

- [Use the CLI](/docs/platform/access/cli)
- [Error codes](/docs/platform/reference/errors)
- [Service accounts](/docs/iam/service-accounts)

