# Does a Twilio SendGrid Mail API success response mean the outcome happened?

> Does a Twilio SendGrid Mail API success response mean the outcome happened? Certification Provisional.

Canonical: https://provely.sh/verify/sendgrid  
Last reviewed: 2026-09-05  
Skill version: 0.1.0  
Certification: provisional  

**No. Twilio SendGrid Mail API returns a success response when it accepts the request. The message then holds one of 7 states. Only `delivered` is terminal success. Provely proves `bounced`, `delivered` and `processed` as separate promises.**

*Skill facts from the signed manifest.*

| Fact | Value |
| --- | --- |
| Skill version | `0.1.0` |
| Publisher | Built and signed by Provely. |
| Certification | Provisional (score 49 of 100) |
| Last conformance run | 2026-09-05T12:00:00Z: 43 of 43 cases passed, 0 critical false VERIFIED |
| Provider API versions | `v3` |
| Default provider API version | `v3` |
| Compiled | 2026-09-05T12:00:00Z by compiler 0.1.0 |
| Manifest hash | `19c7a63280020153` |
| Manifest hash check | the document hashes to the value the manifest states |
| Signature | valid, key `provely-skill-2026-09`, trusted by this build |

## What does this page prove?

| Claim | Proven by | Evidence | Status |
| --- | --- | --- | --- |
| A bounce event with the type bounce states it. A block states the type blocked, and a block never satisfies this level. | [sendgrid.email.bounced](/verify/sendgrid/sendgrid.email.bounced) | E3 | proven |
| The delivered event of this message states it. It is the first event that a system outside Twilio SendGrid decides. | [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) | E3 | proven |
| The processed event of this message states it. The 202 response does not: it carries no identifier and no promise. | [sendgrid.email.processed](/verify/sendgrid/sendgrid.email.processed) | E3 | proven |
| An outcome outside Twilio SendGrid Mail API, such as a bank credit or a person who read a message | not proven | no E5 channel | not proven |
| The agent report that the action worked | never counts | E0 | not proven |

## Which completion levels does the Twilio SendGrid Mail API skill expose?

Each level is one promise with one contract. An agent picks the level that matches the promise it makes. It cannot upgrade a level. Read the [completion level](/glossary/completion-level) definition.

| Level | Contract | Promise | Evidence | Certification |
| --- | --- | --- | --- | --- |
| `bounced` | [sendgrid.email.bounced](/verify/sendgrid/sendgrid.email.bounced) v1.0.0 | A bounce event with the type bounce states it. A block states the type blocked, and a block never satisfies this level. | E3 | Provisional |
| `delivered` | [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) v1.0.0 | The delivered event of this message states it. It is the first event that a system outside Twilio SendGrid decides. | E3 | Provisional |
| `processed` | [sendgrid.email.processed](/verify/sendgrid/sendgrid.email.processed) v1.0.0 | The processed event of this message states it. The 202 response does not: it carries no identifier and no promise. | E3 | Provisional |

## What is the Twilio SendGrid Mail API lifecycle?

### Which states can a `sendgrid.message` be in?

| State | Class | Verdict | Meaning | Source |
| --- | --- | --- | --- | --- |
| `accepted` | transitional | PENDING | The service answered 202 and accepted the request. No event states more. | [sendgrid.openapi](https://raw.githubusercontent.com/twilio/sendgrid-oai/main/spec/json/tsg_mail_v3.json) |
| `processed` | transitional | PENDING | Twilio SendGrid accepted the message and can deliver it. No receiving server saw it. | [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) |
| `deferred` | transitional | PENDING | The receiving server rejected the message temporarily. Twilio SendGrid retries for 72 hours. | [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) |
| `blocked` | transitional | PENDING | The receiving server denied the message temporarily. It can accept the message at a later time. | [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) |
| `delivered` | terminal success | VERIFIED | Twilio SendGrid delivered the message to the receiving server, and the server accepted it. | [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) |
| `bounced` | terminal failure | FAILED | The receiving server denied the message permanently. The bounce event states type bounce. | [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) |
| `dropped` | terminal failure | FAILED | Twilio SendGrid dropped the message. The message never reached a receiving server. | [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) |

In `sendgrid.message` under provider API version `v3`, `delivered` is the only state that means terminal success. Every other state gives PENDING, FAILED, or UNVERIFIABLE.

Source: https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event (retrieved 2026-09-08)

## How does Provely tie the evidence to this exact operation?

A matching state that already existed must not verify. Every contract names the [correlation](/glossary/correlation) keys that bind the evidence to the operation, and the [idempotency](/glossary/idempotency) key that stops a duplicate side effect.

| Strategy | Assurance | Keys | Required | Window |
| --- | --- | --- | --- | --- |
| `resource_id` | strong | provely_operation_id from `$action.result.provely_operation_id` | yes | none |
| `fingerprint` | weak | email from `$input.to` | no | 600000 ms |

*Figure: The skill reads the channels below. It prefers the ones furthest from the action.*

- E0 agent assertion: never sufficient.
- E1 action response: the provider acknowledged the request.
- E2 provider readback: the runtime read the resource back.
- E3 provider event: the provider reported the change.
- E4 independent system: a system outside the action path agrees.
- E5 external outcome: the result is observable in the world.

## Which evidence channels does the skill read?

The runtime prefers the channel that is more independent from the action path. Read the [evidence level](/glossary/evidence-level) definition. An [acknowledgement](/glossary/acknowledgement) from Twilio SendGrid Mail API is E1 and never terminal success.

| Channel | Level | Independence | Verifier | Deterministic | Typical latency |
| --- | --- | --- | --- | --- | --- |
| `send_action_response` | E1 | same response | `action_result` | yes | not stated |
| `delivered_events` | E3 | provider event | `webhook` | no | 5000 ms |
| `dropped_events` | E3 | provider event | `webhook` | no | 5000 ms |
| `hard_bounce_events` | E3 | provider event | `webhook` | no | 5000 ms |
| `processed_by_recipient` | E3 | provider event | `webhook` | no | 5000 ms |
| `processed_events` | E3 | provider event | `webhook` | no | 5000 ms |

## Which ways can a Twilio SendGrid Mail API action look done and not be?

| Contract | Case | Rule | Verdict |
| --- | --- | --- | --- |
| [sendgrid.email.bounced](/verify/sendgrid/sendgrid.email.bounced) | wrong subject | The message went to a different recipient than the intent named. | CONTRADICTED |
| [sendgrid.email.bounced](/verify/sendgrid/sendgrid.email.bounced) | pre existing state | The earliest event of this message is older than the operation. It proves nothing. | CONTRADICTED |
| [sendgrid.email.bounced](/verify/sendgrid/sendgrid.email.bounced) | duplicate side effect | Twilio SendGrid processed more than one message for this recipient since the operation started. Do not retry. | CONTRADICTED |
| [sendgrid.email.bounced](/verify/sendgrid/sendgrid.email.bounced) | observed state | The receiving server accepted the message. It did not bounce. | CONTRADICTED |
| [sendgrid.email.bounced](/verify/sendgrid/sendgrid.email.bounced) | observed state | Twilio SendGrid dropped the message. It never reached a receiving server. | FAILED |
| [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) | wrong subject | The message went to a different recipient than the intent named. | CONTRADICTED |
| [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) | pre existing state | The earliest event of this message is older than the operation. It proves nothing. | CONTRADICTED |
| [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) | duplicate side effect | Twilio SendGrid processed more than one message for this recipient since the operation started. Do not retry. | CONTRADICTED |
| [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) | observed state | The receiving server denied the message permanently. | FAILED |
| [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) | observed state | Twilio SendGrid dropped the message. It never reached a receiving server. | FAILED |
| [sendgrid.email.delivered](/verify/sendgrid/sendgrid.email.delivered) | observed state | Twilio SendGrid holds the message and no event states an end. The runtime observes again later. | PENDING |
| [sendgrid.email.processed](/verify/sendgrid/sendgrid.email.processed) | wrong subject | The message went to a different recipient than the intent named. | CONTRADICTED |
| [sendgrid.email.processed](/verify/sendgrid/sendgrid.email.processed) | pre existing state | The earliest event of this message is older than the operation. It proves nothing. | CONTRADICTED |
| [sendgrid.email.processed](/verify/sendgrid/sendgrid.email.processed) | duplicate side effect | Twilio SendGrid processed more than one message for this recipient since the operation started. Do not retry. | CONTRADICTED |
| [sendgrid.email.processed](/verify/sendgrid/sendgrid.email.processed) | observed state | Twilio SendGrid dropped the message. It never reached a receiving server. | FAILED |

## What did the last conformance run show?

*The six confidence dimensions of the signed manifest.*

| Dimension | Score | Maximum |
| --- | --- | --- |
| Documentation | 14 | 20 |
| Schema alignment | 0 | 15 |
| Lifecycle certainty | 20 | 20 |
| Evidence strength | 16 | 20 |
| Causal correlation | 15 | 15 |
| Sandbox conformance | 10 | 10 |
| Raw score | 75 | 100 |
| Score after the caps | 49 | 100 |

The raw score is 75. One hard cap applies, so the score is 49 and the level is Provisional.

*Why the score is capped.*

| Reason | Highest score it allows |
| --- | --- |
| 9 uncertainty records are open. The lowest cap is 49. | 49 |

*The score and the level of each contract.*

| Contract | Raw score | Score after the caps | Certification |
| --- | --- | --- | --- |
| `sendgrid.email.bounced` | 75 | 49 | Provisional |
| `sendgrid.email.delivered` | 75 | 49 | Provisional |
| `sendgrid.email.processed` | 75 | 49 | Provisional |

> The weakest contract is sendgrid.email.bounced. It scores 49 and reaches Provisional. The package level is Provisional, because a package level never rises above its weakest contract. Read the level of the contract you use.

The last conformance run on 2026-09-05T12:00:00Z passed 43 of 43 cases with 0 critical false VERIFIED. One critical false VERIFIED rejects a skill.

*The conformance result by case class.*

| Case class | Passed | Total |
| --- | --- | --- |
| duplicate side effect | 3 | 3 |
| error after execution | 3 | 3 |
| error before execution | 3 | 3 |
| evidence unavailable | 3 | 3 |
| pre existing state | 3 | 3 |
| stale readback | 3 | 3 |
| still transitional | 3 | 3 |
| terminal failure | 3 | 3 |
| terminal success | 3 | 3 |
| timeout after commit | 3 | 3 |
| version mismatch | 3 | 3 |
| webhook duplicate | 3 | 3 |
| webhook out of order | 3 | 3 |
| wrong subject | 3 | 3 |
| wrong terminal state | 1 | 1 |

The conformance artifact digest is `c5e289cd43907f74`. The harness signs the run, so a reader can check that these numbers come from that run.

## What remains uncertain?

> The level is Provisional because of it. 9 uncertainty records are open. The lowest cap is 49. Provely does not guess a rule that a source does not state.

## Where do these facts come from?

Every claim above cites a source assertion in the skill provenance. The compiler records the source, its hash, and the retrieval date. A page never states a provider rule without one.

| Source | Kind | Retrieved | Excerpt |
| --- | --- | --- | --- |
| [sendgrid.activity](https://raw.githubusercontent.com/twilio/sendgrid-oai/main/spec/json/tsg_email_activity_v3.json) | openapi | 2026-09-08 | trimmed |
| [sendgrid.docs.activity](https://www.twilio.com/docs/sendgrid/api-reference/email-activity) | docs | 2026-09-08 | authored |
| [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) | docs | 2026-09-08 | authored |
| [sendgrid.docs.mail](https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send) | docs | 2026-09-08 | authored |
| [sendgrid.docs.webhook](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/getting-started-event-webhook) | docs | 2026-09-08 | authored |
| [sendgrid.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) | event sample | 2026-09-08 | authored |
| [sendgrid.openapi](https://raw.githubusercontent.com/twilio/sendgrid-oai/main/spec/json/tsg_mail_v3.json) | openapi | 2026-09-08 | trimmed |

## How do I verify a Twilio SendGrid Mail API action?

### Verify a Twilio SendGrid Mail API action with Provely

1. **Begin the operation.** Call `begin` with the contract `sendgrid.email.bounced` and the input. Keep the operation id.
2. **Make the Twilio SendGrid Mail API call you make today.** Send the request with the correlation metadata that `begin` returned.
3. **Submit the acknowledgement.** Call `action_result` with the Twilio SendGrid Mail API response. This is evidence level E1. It is not completion.
4. **Verify.** Call `verify`. The runtime reads `send_action_response`, `delivered_events`, `dropped_events`, `hard_bounce_events`, `processed_by_recipient` and `processed_events` and evaluates the contract.
5. **Report the verdict exactly as returned.** VERIFIED comes with a signed receipt. PENDING comes with the operation id. CONTRADICTED and UNVERIFIABLE are not success.

## Questions developers ask

### Does the `bounced` level prove the `processed` level?

No. A bounce event with the type bounce states it. A block states the type blocked, and a block never satisfies this level. The processed event of this message states it. The 202 response does not: it carries no identifier and no promise. Use `sendgrid.email.processed` to prove `processed`.

### What does the agent say while Twilio SendGrid Mail API reports `accepted`, `processed`, `deferred` and `blocked`?

It says: "The action is accepted but not yet verified. Operation: <id>." The verdict is PENDING. The runtime observes again on the contract timing policy.

### Which Twilio SendGrid Mail API API versions does the skill support?

`v3`. An operation on another version returns UNVERIFIABLE with the reason `version_unsupported`. The runtime never guesses.

### Does Provely need write access to Twilio SendGrid Mail API?

No. The agent keeps its write key. The verifier reads with a separate read-only credential where Twilio SendGrid Mail API permits it, and it never shares that credential with the agent.

## Read next

- [Read the sendgrid.email.bounced contract](https://provely.sh/verify/sendgrid/sendgrid.email.bounced)
- [Read the sendgrid.email.delivered contract](https://provely.sh/verify/sendgrid/sendgrid.email.delivered)
- [Read the sendgrid.email.processed contract](https://provely.sh/verify/sendgrid/sendgrid.email.processed)
- [Read the GitHub REST API verification page](https://provely.sh/verify/github)
- [Read the HubSpot CRM API verification page](https://provely.sh/verify/hubspot)
- [See every integration](https://provely.sh/verify)
- [Verify Twilio SendGrid Mail API actions from Claude Code](https://provely.sh/agents/claude-code)
- [Verify Twilio SendGrid Mail API actions from Cursor](https://provely.sh/agents/cursor)
- [See every agent integration](https://provely.sh/agents)
- [Open the quick start](https://provely.sh/docs/quick-start)
- [Read how Provely records integration uptime](https://provely.sh/docs/uptime)
- [Read the completion level definition](https://provely.sh/glossary/completion-level)
