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

# API Overview

> Base URLs, authentication, response formats, and error handling for the M2M Partner API

## Base URLs

| Environment | Base URL                                |
| ----------- | --------------------------------------- |
| Sandbox     | `https://m2m-backend-qa.up.railway.app` |

<Note>
  Always use the sandbox environment for development and testing.
</Note>

## Authentication

All API requests require authentication via the `X-API-Key` header:

```bash theme={null}
curl -X POST https://m2m-backend-qa.up.railway.app/partner/links \
  -H "X-API-Key: m2m_test_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"referenceId": "user_123"}'
```

<ParamField header="X-API-Key" type="string" required>
  Your API key. Use `m2m_test_*` for sandbox.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json` for all POST/PUT requests.
</ParamField>

See the [Authentication guide](/m2m/authentication) for details on managing API keys.

## Response format

All successful responses follow this structure:

```json theme={null}
{
  "success": true,
  "data": {
    // Response data varies by endpoint
  }
}
```

<ResponseField name="success" type="boolean" required>
  Always `true` for successful responses.
</ResponseField>

<ResponseField name="data" type="object" required>
  The response payload. Structure varies by endpoint.
</ResponseField>

## Error responses

When an error occurs, the response includes an error code and message:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "The referenceId field is required"
  }
}
```

<ResponseField name="success" type="boolean" required>
  Always `false` for error responses.
</ResponseField>

<ResponseField name="error" type="object" required>
  Error details.

  <Expandable title="Error properties">
    <ResponseField name="code" type="string" required>
      Machine-readable error code.
    </ResponseField>

    <ResponseField name="message" type="string" required>
      Human-readable error description.
    </ResponseField>
  </Expandable>
</ResponseField>

### HTTP status codes

| Status | Description                                                     |
| ------ | --------------------------------------------------------------- |
| `200`  | Success                                                         |
| `201`  | Created (for POST requests that create resources)               |
| `400`  | Bad Request - Invalid parameters                                |
| `401`  | Unauthorized - Invalid or missing API key                       |
| `403`  | Forbidden - Valid key but insufficient permissions              |
| `404`  | Not Found - Resource doesn't exist                              |
| `409`  | Conflict - Resource already exists (e.g., active link for user) |
| `429`  | Too Many Requests - Rate limit exceeded                         |
| `500`  | Internal Server Error                                           |

### Common error codes

| Code                    | Description                       |
| ----------------------- | --------------------------------- |
| `UNAUTHORIZED`          | Missing or invalid authentication |
| `INVALID_API_KEY`       | API key is invalid or revoked     |
| `PARTNER_SUSPENDED`     | Partner account is suspended      |
| `INVALID_REQUEST`       | Request validation failed         |
| `RESOURCE_NOT_FOUND`    | Requested resource doesn't exist  |
| `ACTIVE_LINK_EXISTS`    | User already has an active link   |
| `LINK_EXPIRED`          | Magic link has expired            |
| `REFERENCE_ID_MISMATCH` | Reference ID doesn't match        |

## Rate limiting

The API enforces rate limits to ensure fair usage:

| Endpoint        | Limit                |
| --------------- | -------------------- |
| Create Link     | 100 requests/minute  |
| Other endpoints | 1000 requests/minute |

When you exceed the rate limit, you'll receive a `429 Too Many Requests` response:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please retry after 60 seconds."
  }
}
```

<Tip>
  Implement exponential backoff in your integration to handle rate limiting gracefully.
</Tip>

## Pagination

List endpoints support pagination using `limit` and `offset` parameters:

<ParamField query="limit" type="integer" default="20">
  Maximum number of results to return. Range: 1-100.
</ParamField>

<ParamField query="offset" type="integer" default="0">
  Number of results to skip for pagination.
</ParamField>

Paginated responses include metadata:

```json theme={null}
{
  "success": true,
  "data": {
    "items": [...],
    "pagination": {
      "total": 150,
      "limit": 20,
      "offset": 0,
      "hasMore": true
    }
  }
}
```

## Idempotency

For POST requests, you can include an `Idempotency-Key` header to ensure the request is processed only once:

```bash theme={null}
curl -X POST https://m2m-backend-qa.up.railway.app/partner/links \
  -H "X-API-Key: m2m_test_your_api_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-12345" \
  -d '{"referenceId": "user_123"}'
```

If you retry a request with the same `Idempotency-Key`, you'll receive the same response as the original request.

## Available endpoints

<CardGroup cols={2}>
  <Card title="Create Link" icon="link" href="/m2m/api-reference/create-link">
    Generate a magic link for your user.
  </Card>
</CardGroup>
