> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpalm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> How to authenticate requests to the Palm API.

export const iconProps = (variant = "default") => {
  const iconVariants = {
    default: "palm-icon-default",
    horizontal: "palm-icon-horizontal",
    stack: "palm-icon-stack",
    navigation: "palm-icon-navigation",
    darkHorizontal: "palm-icon-dark-horizontal",
    dark_stack: "palm-icon-dark-stack",
    getStarted: "palm-icon-get-started"
  };
  return iconVariants[variant] ?? iconVariants.default;
};

export const PalmCard = ({title, description, icon, variant = "default", href, items}) => {
  if (variant === "getStarted") {
    return <div data-card className="pc-wrapper-get-started flex flex-col gap-4 border border-[rgba(4,44,47,0.1)] rounded-2xl p-6">
        <div className="pc-wrapper-inner-get-started">
          {icon !== undefined && <div className="pc-icon-container-get-started">{icon}</div>}
          {title !== undefined && <span className="pc-title-get-started">{title}</span>}
        </div>
        {items && items.length > 0 && <ul className="pc-items-get-started">
            {items.map((item, i) => <li key={i}>
                <a href={item.href} className="pc-item-link-get-started">{item.label}</a>
              </li>)}
          </ul>}
      </div>;
  }
  const variants = {
    default: {
      wrapper: "pc-wrapper-default",
      title: "pc-title",
      description: "pc-description"
    },
    horizontal: {
      wrapper: "pc-wrapper-card",
      title: "pc-title-horizontal",
      description: "pc-description"
    },
    stack: {
      wrapper: "pc-wrapper-stack",
      title: "pc-title-stack",
      description: "pc-description"
    },
    darkHorizontal: {
      wrapper: "pc-wrapper-dark-horizontal",
      title: "pc-title-dark-horizontal",
      description: "pc-description-dark-horizontal"
    },
    navigation: {
      wrapper: "pc-wrapper-navigation",
      title: "pc-title-navigation",
      description: "pc-description-navigation"
    },
    dark_stack: {
      icon: "pc-icon-card",
      title: "pc-title",
      description: "pc-description"
    }
  };
  const styles = variants[variant] ?? variants.default;
  const inner = <a data-card href={href ? href : '#'} className={`no-underline flex flex-col h-full items-start gap-4 p-6 rounded-2xl hover:opacity-80 transition-opacity ${styles.wrapper}`}>
      {icon !== undefined && <span className="icon-wrapper">{icon}</span>}
      {(title !== undefined || description !== undefined) && <div className="flex flex-col min-w-0">
          {title !== undefined && <span className={styles.title}>{title}</span>}
          {description !== undefined && <span className={styles.description}>{description}</span>}
        </div>}
    </a>;
  return inner;
};

All API requests are authenticated using API keys created in Palm Console ([platform.getpalm.com](https://platform.getpalm.com)).

***

## API keys

API keys are long-lived credentials used for all server-side API calls. They're created and managed in Console.

### Key format

The key prefix tells you the environment:

| Prefix                                                           | Environment | Billing    |
| ---------------------------------------------------------------- | ----------- | ---------- |
| <span className="initial-medium green-wrapper">`sk_test_`</span> | Test        | Not billed |
| <span className="initial-medium green-wrapper">`sk_live_`</span> | Production  | Billed     |

### Usage

Include the API key in the `Authorization` header as a Bearer token:

```bash wrap Bash theme={null}
curl -X POST https://api.getpalm.com/v1/business/registry/search \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer sk_test_...' \
  -d '{
    "name": "Acme Corporation",
    "registration_jurisdiction": "US-CA"
  }'
```

### Key security

When you create an API key, the raw key is returned once. Palm stores a cryptographic hash — not the key itself. If you lose a key, you'll need to create a new one.

Each API key is tied to one organization. All requests authenticated with that key operate within that organization's context.

### Test vs production

The key prefix determines the **mode**. Test keys run in an isolated sandbox — never billed, never touching real filings or providers — and return production-shaped responses and webhooks so you can build a full integration before going live. See [Test mode](/get-started/test-mode) for how it works, deterministic verification results, and simulating filing outcomes.

## Error handling

| Status code                                                             | Meaning                                         |
| ----------------------------------------------------------------------- | ----------------------------------------------- |
| <span className="initial-bold-error">`400 Bad Request`</span>           | Invalid request parameters.                     |
| <span className="initial-bold-error">`401 Unauthorized`</span>          | Missing or invalid credentials.                 |
| <span className="initial-bold-error">`403 Forbidden`</span>             | Valid credentials but insufficient permissions. |
| <span className="initial-bold-error">`404 Not Found`</span>             | Resource not found.                             |
| <span className="initial-bold-error">`429 Too Many Requests`</span>     | Rate limit exceeded.                            |
| <span className="initial-bold-error">`500 Internal Server Error`</span> | Server error.                                   |

Common causes of `401` errors: missing `Authorization` header, malformed Bearer token, or expired / revoked API key.

Error responses follow the [RFC 7807 Problem Details](https://tools.ietf.org/html/rfc7807) format:

```json wrap JSON theme={null}
{
  "type": "https://api.getpalm.com/problems/validation_error",
  "title": "Validation Error",
  "status": 400,
  "detail": "Request validation failed",
  "instance": "/v1/business/registry/search"
}
```

## Best practices

* **Store API keys securely:** Use environment variables or a secrets manager. Never commit keys to source control.
* **Use test keys for development:** Reserve `sk_live_` keys for production systems.
* **Rotate keys periodically:** Create new keys and deprecate old ones on a regular schedule.
* **Monitor key usage:** Check Console for unusual activity patterns.

## Rate limiting

All authenticated requests are subject to rate limits. When you exceed the limit, the API returns `429 Too Many Requests` with the following headers:

| Header                                                              | Description                               |
| ------------------------------------------------------------------- | ----------------------------------------- |
| <span className="initial-bold-error">`X-RateLimit-Limit`</span>     | Maximum requests per minute.              |
| <span className="initial-bold-error">`X-RateLimit-Remaining`</span> | Requests remaining in the current window. |
| <span className="initial-bold-error">`X-RateLimit-Reset`</span>     | Unix timestamp when the window resets.    |

Back off and retry after the reset window.

## Next steps

<div className="grid lg:grid-cols-2 gap-6 mt-6">
  <PalmCard variant="navigation" title="Verify a business" description="Confirm that a business entity is real, registered, and in good standing." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/verify/verify-a-business" />

  <PalmCard variant="navigation" title="Search the registry" description="Search all US registered businesses in the network by name, jurisdiction, or location." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/onboard/registry-search" />
</div>
