> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.upshift.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.upshift.dev/_mcp/server.

# Conventions

### Object IDs

Upshift-generated identifiers contain the type of an object and a globally unique identifier. This enables humans to easily understand what
kind of object an ID refers to.

Here's an example of an app ID:

```
  app_01jhb4nyd9fahvpca24wtwfcxq
  └──┘ └────────────────────────┘
  type    uuid suffix (base32)
```

Upshift Object IDs follow the [TypeID spec](https://github.com/jetify-com/typeid).

### Updates

We use HTTP `PATCH` requests to update resources. The behavior of `PATCH` is to only update the fields that are provided in the request
body.

To remove an optional field, the client should send the field with a value of `null`. Note that attempting to set a required field to
`null` will result in a `422 UnprocessableContentError` error.

Example `PATCH /developer/apps/v1/:id` request body:

```json
{
    // This will result in a 422 error, as name cannot be set to null
    "name": null,
    "listingInfo": {
        // Update the short description field
        "shortDescription": "Updated short description",
        // Remove the optional long description field
        "longDescription": null
    }
    // All omitted app fields will be unchanged
}
```

> **Warning**
>
> Some client libraries may pad request bodies with null values. This will cause issues with our update endpoints.

### Pagination

We use pagination in our API to make sure that we don’t return too much data at once. Our `list` endpoint shapes extend the `Page` type:

```yaml
Page:
    nextCursor: optional<string>
    prevCursor: optional<string>
```

### Unions

We use unions to represent a type that can be one of several different types. When a union shape is used, our union discriminant will
always be the `type` field unless otherwise specified.

As mentioned in [Breaking Changes](/breaking-changes), we expect that it is a non-breaking change to add a new union member to a union
type. This means that if you handle a union field in a response, we expect you to gracefully handle an `_other` case. This allows us to
better serve and improve our APIs at a quick velocity without breaking your code.