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

# Get Form

GET https://api.pinnacle.sh/forms/{id}

Retrieve a form by id. Includes submission count, last submission timestamp, and archive state.

Reference: https://docs.pinnacle.sh/api-reference/forms/get-form

## Authentication

- `PINNACLE-API-KEY` header (required) — API Key authentication via header

## Request

### Path parameters

- `id` (string, required) — The unique identifier of the form you want to retrieve. &#x20;This identifier is a string that always begins with the prefix `form_`, for example: `form_Oy2n7iUoi9CJwUU6`. It's returned on every form response (`Form.id`) and by [`POST /forms/send`](/api-reference/forms/send-form) (`response.form.id`).

## Response

### 200

The form.

- `id` (string, required) — Form id (starts with `form_`).
- `url` (string, required) — Public shareable URL of the form (`https://forms.pinnacle.sh/{form_id}`).
- `name` (string, required, nullable) — Human-readable name for the form. Rendered as the form's title.
- `description` (string, required, nullable) — Longer description rendered below the title.
- `fields` (list of FormField, required) — Ordered list of fields the recipient fills out.
- `can_update` (boolean, required) — When true, the recipient can reopen the submission URL and edit their answers. When false, the URL becomes read-only after the first submit.
- `expires_at` (string, required, nullable) — After this timestamp the form stops accepting submissions. Null means no expiration.
- `theme_override` (FormThemeOverride, required, nullable) — Per-form theme tweaks layered on top of your team's default theme. Null means the team defaults are used as-is.
- `submission_count` (integer, required) — Count of distinct completed submissions for this form. Does not increment on edits to an existing `can_update=true` submission.
- `last_submitted_at` (string, required, nullable) — Timestamp of the most recent submission event. Updated on each new submit and on each edit of a `can_update=true` submission.
- `archived_at` (string, required, nullable) — When set, the form is archived (soft-deleted) and cannot accept new submissions or be updated. Restore by PATCHing `archived_at` back to null.
- `created_at` (string, required) — ISO 8601 timestamp of when the form was created.
- `updated_at` (string, required) — ISO 8601 timestamp of the most recent form mutation.

## Errors

### 400 Bad Request Error

Validation failed. The payload has missing required fields and/or invalid types.&#x20; See [https://zod.dev/error-formatting](https://zod.dev/error-formatting) for more information.

- `description` (string, required) — Human-readable summary of validation failures.
- `errors` (ZodErrorErrors, required) — Structured dictionary of issues containing two main sections: - `errors`: Array of global validation errors not tied to specific fields - `properties`: Object mapping field names to their specific validation errors, where each field contains an `errors` array

### 401 Unauthorized Error

The request lacks valid authentication credentials or the provided credentials are invalid.&#x20; Ensure you're including a valid API key in the request headers and that your account has the necessary permissions to access this endpoint.

- `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code.

### 404 Not Found Error

The requested resource could not be found.&#x20; This may occur if the identifier is incorrect, the resource has been deleted, or you don't have permission to access it.

- `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code.

### 500 Internal Server Error

An unexpected error occurred on Pinnacle's servers while processing your request.&#x20; If this error persists, please contact support with the request details.

- `error` (string, required) — Human-readable description of the error that occurred, corresponding to the HTTP status code.

## Types

### FormField

A single field definition inside a form. Discriminated by `type`.

- `type`: `text` (text)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max_length` (integer, optional) — Maximum number of characters the submitter may enter.
  - `min_length` (integer, optional) — Minimum number of characters the submitter must enter.
  - `pattern` (string, optional) — Regex the value must match. Validated server-side with RE2, so patterns that enable catastrophic backtracking (backreferences, lookarounds) are rejected at form creation.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `textarea` (textarea)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max_length` (integer, optional) — Maximum number of characters the submitter may enter.
  - `min_length` (integer, optional) — Minimum number of characters the submitter must enter.
  - `pattern` (string, optional) — Regex the value must match. Same RE2 safety check as `TextField.pattern`.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `address` (address)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max_length` (integer, optional) — Maximum number of characters in the selected address.
  - `min_length` (integer, optional) — Minimum number of characters in the selected address.
  - `pattern` (string, optional) — Regex the value must match. Same RE2 safety check as `TextField.pattern`. Rarely needed for addresses — usually left off.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `email` (email)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `url` (url)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `phone` (phone)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `number` (number)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max` (double, optional) — Maximum accepted value.
  - `min` (double, optional) — Minimum accepted value.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
  - `step` (double, optional) — Increment between valid values. For example, `step: 0.5` lets the user enter 1, 1.5, 2, etc.
- `type`: `range` (range)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max` (double, optional, default: 100) — Upper bound of the slider.
  - `min` (double, optional, default: 0) — Lower bound of the slider.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
  - `step` (double, optional) — Increment between adjacent slider stops.
- `type`: `rating` (rating)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max` (integer, optional, default: 5) — Number of stars rendered.
  - `min` (integer, optional, default: 0) — Minimum allowed rating. `0` means the submitter can clear their selection.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `date` (date)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max` (string, optional) — Latest selectable date as `YYYY-MM-DD`.
  - `min` (string, optional) — Earliest selectable date as `YYYY-MM-DD`.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `time` (time)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max` (string, optional) — Latest selectable time as `HH:MM` (24-hour).
  - `min` (string, optional) — Earliest selectable time as `HH:MM` (24-hour).
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `datetime` (datetime)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max` (string, optional) — Latest selectable instant as an ISO 8601 timestamp.
  - `min` (string, optional) — Earliest selectable instant as an ISO 8601 timestamp.
  - `placeholder` (string, optional) — Ghost text shown inside the input while it's empty.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `color` (color)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `select` (select)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `options` (list of FormFieldOption, required) — Choices shown in the dropdown. At least one is required.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `placeholder` (string, optional) — Placeholder row shown when no option is selected (e.g. "Select…").
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `radio` (radio)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `options` (list of FormFieldOption, required) — Choices shown as radio buttons. At least one is required.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.
- `type`: `checkbox` (checkbox)
  - `key` (string, required) — Programmatic key used as the property name in the submission payload. Must start with a letter or underscore; letters, digits, and underscores only.
  - `label` (string, required) — Text shown above the input.
  - `help_text` (string, optional) — Small caption rendered under the input to give the submitter extra context.
  - `max_selected` (integer, optional) — Maximum number of boxes the submitter may check. Extra boxes become uninteractive once the cap is reached.
  - `min_selected` (integer, optional) — Minimum number of boxes the submitter must check.
  - `options` (list of FormFieldOption, optional) — Choices shown as checkboxes. Omit to render a single boolean checkbox.
  - `required` (boolean, optional, default: false) — When true, the submitter must provide a value. Default false.

### FormThemeOverride

Sparse override layered on top of your team's theme. Every field is optional; provided fields replace the corresponding team defaults at render time. URL fields must use `https://`.

- `logo_url` (string, optional, nullable) — Logo displayed at the top of the form. Square images render as an inline mark; wide landscape images render as a full-width banner.
- `favicon_url` (string, optional, nullable) — Favicon shown in the browser tab when the form page loads.
- `theme_mode` (enum, optional) — Rendering mode. `light` forces the light palette, `dark` forces dark, and `auto` follows the respondent's OS-level appearance setting.
  - Allowed values: `light`, `dark`, `auto`
- `colors` (FormThemeOverrideColors, optional) — Per-mode palette overrides. Each mode is an object with optional `primary`, `background`, and `text` hex colors. Omit a mode to inherit the team default for it.
- `font_family` (enum, optional) — Typeface stack. `system` uses the respondent's OS default sans-serif.
  - Allowed values: `inter`, `system`, `serif`, `mono`, `rounded`
- `corner_radius` (enum, optional) — Border-radius preset for cards, inputs, and buttons.
  - Allowed values: `sharp`, `rounded`, `pill`
- `content_alignment` (enum, optional) — Horizontal alignment for the form header (title, description, logo).
  - Allowed values: `left`, `center`, `right`
- `background` (FormBackground, optional) — Background layer for the page. Choose solid, gradient, image, or a built-in pattern.
- `submit_button_label` (string, optional) — Text shown on the submit button. Defaults to `Submit`.
- `success_message` (string, optional) — Message shown on the success panel after a successful submit (unless `redirect_url` is set, in which case the respondent is redirected).
- `redirect_url` (string, optional, nullable) — When set, the submitter is redirected here after a successful submit instead of seeing the success panel.
- `privacy_url` (string, optional, nullable) — Link target for the `Privacy` footer link. Omit or set to null to hide the link.
- `terms_url` (string, optional, nullable) — Link target for the `Terms` footer link. Omit or set to null to hide the link.
- `og_image_url` (string, optional, nullable) — Image shown when the form URL is shared in social / messaging link previews (Open Graph).
- `og_description` (string, optional, nullable) — Open Graph description used in link previews. Falls back to the form's `description` when unset.

### ZodErrorErrors

Structured dictionary of issues containing two main sections: - `errors`: Array of global validation errors not tied to specific fields - `properties`: Object mapping field names to their specific validation errors, where each field contains an `errors` array

### FormFieldOption

A single choice inside a `select`, `radio`, or `checkbox` field.

- `value` (string, required) — Machine value sent back in the submission payload.
- `label` (string, required) — Human label rendered in the form.

### FormThemeOverrideColors

Per-mode palette overrides. Each mode is an object with optional `primary`, `background`, and `text` hex colors. Omit a mode to inherit the team default for it.

- `light` (FormColorPalette, optional) — Palette used when the form renders in light mode.
- `dark` (FormColorPalette, optional) — Palette used when the form renders in dark mode.

### FormBackground

Background layer for the form page. Discriminated by `type`.

- `type`: `solid` (solid)
- `type`: `gradient` (gradient)
  - `dark` (FormGradient, required) — Gradient used when the form renders in dark mode.
  - `light` (FormGradient, required) — Gradient used when the form renders in light mode.
- `type`: `image` (image)
  - `blur` (boolean, required) — When true, blurs the background image.
  - `tint_opacity` (integer, required) — Darkening overlay intensity from 0 (no overlay) to 80 (heavy). Helps preserve text contrast over busy images.
  - `url` (string, required) — HTTPS URL of the background image. Must start with `https://`.
  - `zoom` (integer, required) — Scale percentage. 100 is native size; higher values crop the image tighter.
- `type`: `pattern` (pattern)
  - `preset` (enum, required) — Which built-in pattern to render.
    - Allowed values: `noise`, `dots`, `mesh`, `grid`, `waves`, `topo`

### FormColorPalette

Per-mode palette. All three colors are optional; any you omit fall back to the team default for that mode.

- `primary` (string, optional) — Accent color used for the submit button, focus rings, filled checkboxes, and other interactive surfaces.
- `background` (string, optional) — Page background color. Fallback solid color used by Safari chrome tinting and safe-area regions.
- `text` (string, optional) — Body text and label color.

### FormGradient

A single light- or dark-mode gradient stop pair.

- `from` (string, required) — Starting color of the gradient.
- `to` (string, required) — Ending color of the gradient.
- `angle` (enum, required) — Direction the gradient runs. `top-bottom` is vertical; `diagonal` runs top-left → bottom-right.
  - Allowed values: `top-bottom`, `diagonal`

## Examples

**Response**

```json
{
  "id": "form_Oy2n7iUoi9CJwUU6",
  "url": "https://forms.pinnacle.sh/form_Oy2n7iUoi9CJwUU6",
  "name": "Contact request",
  "description": "We'll follow up over SMS or RCS.",
  "fields": [
    {
      "type": "text",
      "key": "full_name",
      "label": "Full name",
      "min_length": 2,
      "required": true
    },
    {
      "type": "email",
      "key": "email",
      "label": "Email",
      "required": true
    }
  ],
  "can_update": false,
  "expires_at": null,
  "theme_override": null,
  "submission_count": 12,
  "last_submitted_at": "2026-04-23T22:15:04.406Z",
  "archived_at": null,
  "created_at": "2026-04-01T12:00:00Z",
  "updated_at": "2026-04-23T22:15:04.430Z"
}
```

**SDK Code**

```python Form
import requests

url = "https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6"

headers = {"PINNACLE-API-KEY": "<apiKey>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript Form
const url = 'https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6';
const options = {method: 'GET', headers: {'PINNACLE-API-KEY': '<apiKey>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Form
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("PINNACLE-API-KEY", "<apiKey>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Form
require 'uri'
require 'net/http'

url = URI("https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["PINNACLE-API-KEY"] = '<apiKey>'

response = http.request(request)
puts response.read_body
```

```java Form
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6")
  .header("PINNACLE-API-KEY", "<apiKey>")
  .asString();
```

```php Form
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6', [
  'headers' => [
    'PINNACLE-API-KEY' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp Form
using RestSharp;

var client = new RestClient("https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6");
var request = new RestRequest(Method.GET);
request.AddHeader("PINNACLE-API-KEY", "<apiKey>");
IRestResponse response = client.Execute(request);
```

```swift Form
import Foundation

let headers = ["PINNACLE-API-KEY": "<apiKey>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.pinnacle.sh/forms/form_Oy2n7iUoi9CJwUU6")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```