# Report SMS outcomes

`POST /api/v1/phone/feedback`

- Authentication: Secret API key as a bearer token
- Billing: Free.
- Group: Phone

Tells Spaw what happened after you sent an SMS to a number: `delivered`, `undelivered` (the carrier reported it could not be delivered), or `abused` (the code was used by someone who was not the recipient, or the number was involved in fraud). Your own reports feed your own later lookups of that number as risk signals with the dataset `delivery-feedback`: a number whose latest report within 90 days is undelivered scores `reported_undelivered` (+50), a number with any abuse report within 90 days scores `reported_abuse` (+60), and a delivery reported after a failure cancels that failure. No other account ever sees your reports.

Numbers are normalised like a lookup; national notation needs a `country` on the item or on the request. Items whose number does not parse as a valid subscriber number are skipped and counted, not rejected. Feedback is free and never logged as a lookup. Outcomes are kept for 180 days.

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | object[] | yes | 1 to 1,000 outcomes per request. |
| `items[].phone` | string | yes | The number, in any common notation. At most 32 characters. |
| `items[].outcome` | string | yes | One of: delivered, undelivered, abused. |
| `items[].country` | string | null | no | An ISO 3166-1 alpha-2 region for a number written without a calling code; overrides the request-level country. |
| `items[].occurred_at` | string | null | no | When it happened. Defaults to now. |
| `country` | string | null | no | An ISO 3166-1 alpha-2 region applied to items that do not name their own, for numbers written without a calling code. |

## Example request

```bash
curl -X POST https://spaw.co/api/v1/phone/feedback \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "phone": "+44 7911 012345",
      "outcome": "undelivered"
    },
    {
      "phone": "(415) 555-0142",
      "country": "US",
      "outcome": "delivered",
      "occurred_at": "2026-09-05T09:00:00Z"
    }
  ]
}'
```

## Responses

### 202 — The outcomes were recorded.

```json
{
    "success": true,
    "data": {
        "recorded": 2,
        "skipped": 0
    }
}
```

### 401 — The key is missing, malformed, or revoked.

```json
{
    "success": false,
    "error": {
        "code": "UNAUTHENTICATED",
        "message": "Provide a valid API key as a bearer token.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 422 — The request body could not be validated; `error.errors` lists the fields.

```json
{
    "success": false,
    "error": {
        "code": "VALIDATION_FAILED",
        "message": "The email field is required.",
        "errors": {
            "email": [
                "The email field is required."
            ]
        },
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 429 — Over 5 requests per second for the key. Retry after the limit resets.

```json
{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

## Error codes

- `UNAUTHENTICATED` — https://spaw.co/docs/errors/UNAUTHENTICATED
- `VALIDATION_FAILED` — https://spaw.co/docs/errors/VALIDATION_FAILED
- `RATE_LIMITED` — https://spaw.co/docs/errors/RATE_LIMITED

---

Canonical page: https://spaw.co/docs/api/report-phone-feedback · OpenAPI document: https://spaw.co/openapi.json · All endpoints: https://spaw.co/docs/api
